diff options
author | Alyssa Ross <hi@alyssa.is> | 2024-03-24 11:04:41 +0100 |
---|---|---|
committer | Alyssa Ross <hi@alyssa.is> | 2024-03-24 11:04:41 +0100 |
commit | 5423cabbbf2b6dec5568f1ecabd288d5d9a642ec (patch) | |
tree | f316a6a921bfefd3a63bd4502c2eb50ff1644f67 /nixpkgs/lib | |
parent | 46a88117a05c3469af5d99433af140c3de8ca088 (diff) | |
parent | 8aa81f34981add12aecada6c702ddbbd0375ca36 (diff) | |
download | nixlib-5423cabbbf2b6dec5568f1ecabd288d5d9a642ec.tar nixlib-5423cabbbf2b6dec5568f1ecabd288d5d9a642ec.tar.gz nixlib-5423cabbbf2b6dec5568f1ecabd288d5d9a642ec.tar.bz2 nixlib-5423cabbbf2b6dec5568f1ecabd288d5d9a642ec.tar.lz nixlib-5423cabbbf2b6dec5568f1ecabd288d5d9a642ec.tar.xz nixlib-5423cabbbf2b6dec5568f1ecabd288d5d9a642ec.tar.zst nixlib-5423cabbbf2b6dec5568f1ecabd288d5d9a642ec.zip |
Merge branch 'nixos-unstable-small' of https://github.com/NixOS/nixpkgs
Diffstat (limited to 'nixpkgs/lib')
-rw-r--r-- | nixpkgs/lib/attrsets.nix | 1866 | ||||
-rw-r--r-- | nixpkgs/lib/customisation.nix | 133 | ||||
-rw-r--r-- | nixpkgs/lib/deprecated.nix | 104 | ||||
-rw-r--r-- | nixpkgs/lib/generators.nix | 209 | ||||
-rw-r--r-- | nixpkgs/lib/kernel.nix | 4 | ||||
-rw-r--r-- | nixpkgs/lib/licenses.nix | 20 | ||||
-rw-r--r-- | nixpkgs/lib/lists.nix | 1704 | ||||
-rw-r--r-- | nixpkgs/lib/systems/default.nix | 4 | ||||
-rw-r--r-- | nixpkgs/lib/tests/misc.nix | 89 | ||||
-rw-r--r-- | nixpkgs/lib/tests/modules/alias-with-priority-can-override.nix | 13 | ||||
-rw-r--r-- | nixpkgs/lib/tests/modules/alias-with-priority.nix | 13 | ||||
-rw-r--r-- | nixpkgs/lib/tests/modules/extendModules-168767-imports.nix | 9 | ||||
-rw-r--r-- | nixpkgs/lib/trivial.nix | 941 |
13 files changed, 3865 insertions, 1244 deletions
diff --git a/nixpkgs/lib/attrsets.nix b/nixpkgs/lib/attrsets.nix index 34054460ba76..de5968b95348 100644 --- a/nixpkgs/lib/attrsets.nix +++ b/nixpkgs/lib/attrsets.nix @@ -1,4 +1,6 @@ -/* Operations on attribute sets. */ +/** + Operations on attribute sets. +*/ { lib }: let @@ -12,35 +14,57 @@ rec { inherit (builtins) attrNames listToAttrs hasAttr isAttrs getAttr removeAttrs; - /* Return an attribute from nested attribute sets. + /** + Return an attribute from nested attribute sets. + + Nix has an [attribute selection operator `. or`](https://nixos.org/manual/nix/stable/language/operators#attribute-selection) which is sufficient for such queries, as long as the number of attributes is static. For example: + + ```nix + (x.a.b or 6) == attrByPath ["a" "b"] 6 x + # and + (x.${f p}."example.com" or 6) == attrByPath [ (f p) "example.com" ] 6 x + ``` + - Nix has an [attribute selection operator `. or`](https://nixos.org/manual/nix/stable/language/operators#attribute-selection) which is sufficient for such queries, as long as the number of attributes is static. For example: + # Inputs - ```nix - (x.a.b or 6) == attrByPath ["a" "b"] 6 x - # and - (x.${f p}."example.com" or 6) == attrByPath [ (f p) "example.com" ] 6 x - ``` + `attrPath` - Example: - x = { a = { b = 3; }; } - # ["a" "b"] is equivalent to x.a.b - # 6 is a default value to return if the path does not exist in attrset - attrByPath ["a" "b"] 6 x - => 3 - attrByPath ["z" "z"] 6 x - => 6 + : A list of strings representing the attribute path to return from `set` - Type: - attrByPath :: [String] -> Any -> AttrSet -> Any + `default` + + : Default value if `attrPath` does not resolve to an existing value + + `set` + + : The nested attribute set to select values from + + # Type + ``` + attrByPath :: [String] -> Any -> AttrSet -> Any + ``` + + # Examples + :::{.example} + ## `lib.attrsets.attrByPath` usage example + + ```nix + x = { a = { b = 3; }; } + # ["a" "b"] is equivalent to x.a.b + # 6 is a default value to return if the path does not exist in attrset + attrByPath ["a" "b"] 6 x + => 3 + attrByPath ["z" "z"] 6 x + => 6 + ``` + + ::: */ attrByPath = - # A list of strings representing the attribute path to return from `set` attrPath: - # Default value if `attrPath` does not resolve to an existing value default: - # The nested attribute set to select values from set: let lenAttrPath = length attrPath; @@ -57,37 +81,57 @@ rec { in attrByPath' 0 set; - /* Return if an attribute from nested attribute set exists. + /** + Return if an attribute from nested attribute set exists. + + Nix has a [has attribute operator `?`](https://nixos.org/manual/nix/stable/language/operators#has-attribute), which is sufficient for such queries, as long as the number of attributes is static. For example: - Nix has a [has attribute operator `?`](https://nixos.org/manual/nix/stable/language/operators#has-attribute), which is sufficient for such queries, as long as the number of attributes is static. For example: + ```nix + (x?a.b) == hasAttryByPath ["a" "b"] x + # and + (x?${f p}."example.com") == hasAttryByPath [ (f p) "example.com" ] x + ``` + + **Laws**: + 1. ```nix + hasAttrByPath [] x == true + ``` + + + # Inputs - ```nix - (x?a.b) == hasAttryByPath ["a" "b"] x - # and - (x?${f p}."example.com") == hasAttryByPath [ (f p) "example.com" ] x - ``` + `attrPath` - **Laws**: - 1. ```nix - hasAttrByPath [] x == true - ``` + : A list of strings representing the attribute path to check from `set` - Example: - x = { a = { b = 3; }; } - hasAttrByPath ["a" "b"] x - => true - hasAttrByPath ["z" "z"] x - => false - hasAttrByPath [] (throw "no need") - => true + `e` - Type: - hasAttrByPath :: [String] -> AttrSet -> Bool + : The nested attribute set to check + + # Type + + ``` + hasAttrByPath :: [String] -> AttrSet -> Bool + ``` + + # Examples + :::{.example} + ## `lib.attrsets.hasAttrByPath` usage example + + ```nix + x = { a = { b = 3; }; } + hasAttrByPath ["a" "b"] x + => true + hasAttrByPath ["z" "z"] x + => false + hasAttrByPath [] (throw "no need") + => true + ``` + + ::: */ hasAttrByPath = - # A list of strings representing the attribute path to check from `set` attrPath: - # The nested attribute set to check e: let lenAttrPath = length attrPath; @@ -103,7 +147,7 @@ rec { in hasAttrByPath' 0 e; - /* + /** Return the longest prefix of an attribute path that refers to an existing attribute in a nesting of attribute sets. Can be used after [`mapAttrsRecursiveCond`](#function-library-lib.attrsets.mapAttrsRecursiveCond) to apply a condition, @@ -120,24 +164,43 @@ rec { hasAttrByPath (attrsets.longestValidPathPrefix p x) x == true ``` - Example: - x = { a = { b = 3; }; } - attrsets.longestValidPathPrefix ["a" "b" "c"] x - => ["a" "b"] - attrsets.longestValidPathPrefix ["a"] x - => ["a"] - attrsets.longestValidPathPrefix ["z" "z"] x - => [] - attrsets.longestValidPathPrefix ["z" "z"] (throw "no need") - => [] - - Type: - attrsets.longestValidPathPrefix :: [String] -> Value -> [String] + + # Inputs + + `attrPath` + + : A list of strings representing the longest possible path that may be returned. + + `v` + + : The nested attribute set to check. + + # Type + + ``` + attrsets.longestValidPathPrefix :: [String] -> Value -> [String] + ``` + + # Examples + :::{.example} + ## `lib.attrsets.longestValidPathPrefix` usage example + + ```nix + x = { a = { b = 3; }; } + attrsets.longestValidPathPrefix ["a" "b" "c"] x + => ["a" "b"] + attrsets.longestValidPathPrefix ["a"] x + => ["a"] + attrsets.longestValidPathPrefix ["z" "z"] x + => [] + attrsets.longestValidPathPrefix ["z" "z"] (throw "no need") + => [] + ``` + + ::: */ longestValidPathPrefix = - # A list of strings representing the longest possible path that may be returned. attrPath: - # The nested attribute set to check. v: let lenAttrPath = length attrPath; @@ -168,19 +231,39 @@ rec { in getPrefixForSetAtIndex v 0; - /* Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`. + /** + Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`. + - Example: - setAttrByPath ["a" "b"] 3 - => { a = { b = 3; }; } + # Inputs - Type: - setAttrByPath :: [String] -> Any -> AttrSet + `attrPath` + + : A list of strings representing the attribute path to set + + `value` + + : The value to set at the location described by `attrPath` + + # Type + + ``` + setAttrByPath :: [String] -> Any -> AttrSet + ``` + + # Examples + :::{.example} + ## `lib.attrsets.setAttrByPath` usage example + + ```nix + setAttrByPath ["a" "b"] 3 + => { a = { b = 3; }; } + ``` + + ::: */ setAttrByPath = - # A list of strings representing the attribute path to set attrPath: - # The value to set at the location described by `attrPath` value: let len = length attrPath; @@ -190,47 +273,89 @@ rec { else { ${elemAt attrPath n} = atDepth (n + 1); }; in atDepth 0; - /* Like `attrByPath`, but without a default value. If it doesn't find the - path it will throw an error. + /** + Like `attrByPath`, but without a default value. If it doesn't find the + path it will throw an error. - Nix has an [attribute selection operator](https://nixos.org/manual/nix/stable/language/operators#attribute-selection) which is sufficient for such queries, as long as the number of attributes is static. For example: + Nix has an [attribute selection operator](https://nixos.org/manual/nix/stable/language/operators#attribute-selection) which is sufficient for such queries, as long as the number of attributes is static. For example: ```nix - x.a.b == getAttrByPath ["a" "b"] x - # and - x.${f p}."example.com" == getAttrByPath [ (f p) "example.com" ] x - ``` - - Example: - x = { a = { b = 3; }; } - getAttrFromPath ["a" "b"] x - => 3 - getAttrFromPath ["z" "z"] x - => error: cannot find attribute `z.z' - - Type: - getAttrFromPath :: [String] -> AttrSet -> Any + x.a.b == getAttrByPath ["a" "b"] x + # and + x.${f p}."example.com" == getAttrByPath [ (f p) "example.com" ] x + ``` + + + # Inputs + + `attrPath` + + : A list of strings representing the attribute path to get from `set` + + `set` + + : The nested attribute set to find the value in. + + # Type + + ``` + getAttrFromPath :: [String] -> AttrSet -> Any + ``` + + # Examples + :::{.example} + ## `lib.attrsets.getAttrFromPath` usage example + + ```nix + x = { a = { b = 3; }; } + getAttrFromPath ["a" "b"] x + => 3 + getAttrFromPath ["z" "z"] x + => error: cannot find attribute `z.z' + ``` + + ::: */ getAttrFromPath = - # A list of strings representing the attribute path to get from `set` attrPath: - # The nested attribute set to find the value in. set: attrByPath attrPath (abort ("cannot find attribute `" + concatStringsSep "." attrPath + "'")) set; - /* Map each attribute in the given set and merge them into a new attribute set. + /** + Map each attribute in the given set and merge them into a new attribute set. + + + # Inputs - Type: - concatMapAttrs :: (String -> a -> AttrSet) -> AttrSet -> AttrSet + `f` - Example: - concatMapAttrs - (name: value: { - ${name} = value; - ${name + value} = value; - }) - { x = "a"; y = "b"; } - => { x = "a"; xa = "a"; y = "b"; yb = "b"; } + : 1\. Function argument + + `v` + + : 2\. Function argument + + # Type + + ``` + concatMapAttrs :: (String -> a -> AttrSet) -> AttrSet -> AttrSet + ``` + + # Examples + :::{.example} + ## `lib.attrsets.concatMapAttrs` usage example + + ```nix + concatMapAttrs + (name: value: { + ${name} = value; + ${name + value} = value; + }) + { x = "a"; y = "b"; } + => { x = "a"; xa = "a"; y = "b"; yb = "b"; } + ``` + + ::: */ concatMapAttrs = f: v: foldl' mergeAttrs { } @@ -239,49 +364,61 @@ rec { ); - /* Update or set specific paths of an attribute set. - - Takes a list of updates to apply and an attribute set to apply them to, - and returns the attribute set with the updates applied. Updates are - represented as `{ path = ...; update = ...; }` values, where `path` is a - list of strings representing the attribute path that should be updated, - and `update` is a function that takes the old value at that attribute path - as an argument and returns the new - value it should be. - - Properties: - - - Updates to deeper attribute paths are applied before updates to more - shallow attribute paths - - - Multiple updates to the same attribute path are applied in the order - they appear in the update list - - - If any but the last `path` element leads into a value that is not an - attribute set, an error is thrown - - - If there is an update for an attribute path that doesn't exist, - accessing the argument in the update function causes an error, but - intermediate attribute sets are implicitly created as needed - - Example: - updateManyAttrsByPath [ - { - path = [ "a" "b" ]; - update = old: { d = old.c; }; - } - { - path = [ "a" "b" "c" ]; - update = old: old + 1; - } - { - path = [ "x" "y" ]; - update = old: "xy"; - } - ] { a.b.c = 0; } - => { a = { b = { d = 1; }; }; x = { y = "xy"; }; } - - Type: updateManyAttrsByPath :: [{ path :: [String]; update :: (Any -> Any); }] -> AttrSet -> AttrSet + /** + Update or set specific paths of an attribute set. + + Takes a list of updates to apply and an attribute set to apply them to, + and returns the attribute set with the updates applied. Updates are + represented as `{ path = ...; update = ...; }` values, where `path` is a + list of strings representing the attribute path that should be updated, + and `update` is a function that takes the old value at that attribute path + as an argument and returns the new + value it should be. + + Properties: + + - Updates to deeper attribute paths are applied before updates to more + shallow attribute paths + + - Multiple updates to the same attribute path are applied in the order + they appear in the update list + + - If any but the last `path` element leads into a value that is not an + attribute set, an error is thrown + + - If there is an update for an attribute path that doesn't exist, + accessing the argument in the update function causes an error, but + intermediate attribute sets are implicitly created as needed + + # Type + + ``` + updateManyAttrsByPath :: [{ path :: [String]; update :: (Any -> Any); }] -> AttrSet -> AttrSet + ``` + + # Examples + :::{.example} + ## `lib.attrsets.updateManyAttrsByPath` usage example + + ```nix + updateManyAttrsByPath [ + { + path = [ "a" "b" ]; + update = old: { d = old.c; }; + } + { + path = [ "a" "b" "c" ]; + update = old: old + 1; + } + { + path = [ "x" "y" ]; + update = old: "xy"; + } + ] { a.b.c = 0; } + => { a = { b = { d = 1; }; }; x = { y = "xy"; }; } + ``` + + ::: */ updateManyAttrsByPath = let # When recursing into attributes, instead of updating the `path` of each @@ -342,96 +479,208 @@ rec { in updates: value: go 0 true value updates; - /* Return the specified attributes from a set. + /** + Return the specified attributes from a set. + + + # Inputs + + `nameList` + + : The list of attributes to fetch from `set`. Each attribute name must exist on the attrbitue set - Example: - attrVals ["a" "b" "c"] as - => [as.a as.b as.c] + `set` - Type: - attrVals :: [String] -> AttrSet -> [Any] + : The set to get attribute values from + + # Type + + ``` + attrVals :: [String] -> AttrSet -> [Any] + ``` + + # Examples + :::{.example} + ## `lib.attrsets.attrVals` usage example + + ```nix + attrVals ["a" "b" "c"] as + => [as.a as.b as.c] + ``` + + ::: */ attrVals = - # The list of attributes to fetch from `set`. Each attribute name must exist on the attrbitue set nameList: - # The set to get attribute values from set: map (x: set.${x}) nameList; - /* Return the values of all attributes in the given set, sorted by - attribute name. + /** + Return the values of all attributes in the given set, sorted by + attribute name. - Example: - attrValues {c = 3; a = 1; b = 2;} - => [1 2 3] + # Type - Type: - attrValues :: AttrSet -> [Any] + ``` + attrValues :: AttrSet -> [Any] + ``` + + # Examples + :::{.example} + ## `lib.attrsets.attrValues` usage example + + ```nix + attrValues {c = 3; a = 1; b = 2;} + => [1 2 3] + ``` + + ::: */ attrValues = builtins.attrValues; - /* Given a set of attribute names, return the set of the corresponding - attributes from the given set. + /** + Given a set of attribute names, return the set of the corresponding + attributes from the given set. + + + # Inputs + + `names` - Example: - getAttrs [ "a" "b" ] { a = 1; b = 2; c = 3; } - => { a = 1; b = 2; } + : A list of attribute names to get out of `set` - Type: - getAttrs :: [String] -> AttrSet -> AttrSet + `attrs` + + : The set to get the named attributes from + + # Type + + ``` + getAttrs :: [String] -> AttrSet -> AttrSet + ``` + + # Examples + :::{.example} + ## `lib.attrsets.getAttrs` usage example + + ```nix + getAttrs [ "a" "b" ] { a = 1; b = 2; c = 3; } + => { a = 1; b = 2; } + ``` + + ::: */ getAttrs = - # A list of attribute names to get out of `set` names: - # The set to get the named attributes from attrs: genAttrs names (name: attrs.${name}); - /* Collect each attribute named `attr` from a list of attribute - sets. Sets that don't contain the named attribute are ignored. + /** + Collect each attribute named `attr` from a list of attribute + sets. Sets that don't contain the named attribute are ignored. + + # Inputs + + `attr` + + : The attribute name to get out of the sets. - Example: - catAttrs "a" [{a = 1;} {b = 0;} {a = 2;}] - => [1 2] + `list` - Type: - catAttrs :: String -> [AttrSet] -> [Any] + : The list of attribute sets to go through + + # Type + + ``` + catAttrs :: String -> [AttrSet] -> [Any] + ``` + + # Examples + :::{.example} + ## `lib.attrsets.catAttrs` usage example + + ```nix + catAttrs "a" [{a = 1;} {b = 0;} {a = 2;}] + => [1 2] + ``` + + ::: */ catAttrs = builtins.catAttrs; - /* Filter an attribute set by removing all attributes for which the - given predicate return false. + /** + Filter an attribute set by removing all attributes for which the + given predicate return false. + + + # Inputs + + `pred` - Example: - filterAttrs (n: v: n == "foo") { foo = 1; bar = 2; } - => { foo = 1; } + : Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute, or `false` to exclude the attribute. - Type: - filterAttrs :: (String -> Any -> Bool) -> AttrSet -> AttrSet + `set` + + : The attribute set to filter + + # Type + + ``` + filterAttrs :: (String -> Any -> Bool) -> AttrSet -> AttrSet + ``` + + # Examples + :::{.example} + ## `lib.attrsets.filterAttrs` usage example + + ```nix + filterAttrs (n: v: n == "foo") { foo = 1; bar = 2; } + => { foo = 1; } + ``` + + ::: */ filterAttrs = - # Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute, or `false` to exclude the attribute. pred: - # The attribute set to filter set: listToAttrs (concatMap (name: let v = set.${name}; in if pred name v then [(nameValuePair name v)] else []) (attrNames set)); - /* Filter an attribute set recursively by removing all attributes for - which the given predicate return false. + /** + Filter an attribute set recursively by removing all attributes for + which the given predicate return false. + + + # Inputs + + `pred` + + : Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute, or `false` to exclude the attribute. + + `set` + + : The attribute set to filter + + # Type + + ``` + filterAttrsRecursive :: (String -> Any -> Bool) -> AttrSet -> AttrSet + ``` - Example: - filterAttrsRecursive (n: v: v != null) { foo = { bar = null; }; } - => { foo = {}; } + # Examples + :::{.example} + ## `lib.attrsets.filterAttrsRecursive` usage example - Type: - filterAttrsRecursive :: (String -> Any -> Bool) -> AttrSet -> AttrSet + ```nix + filterAttrsRecursive (n: v: v != null) { foo = { bar = null; }; } + => { foo = {}; } + ``` + + ::: */ filterAttrsRecursive = - # Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute, or `false` to exclude the attribute. pred: - # The attribute set to filter set: listToAttrs ( concatMap (name: @@ -445,59 +694,84 @@ rec { ) (attrNames set) ); - /* + /** Like [`lib.lists.foldl'`](#function-library-lib.lists.foldl-prime) but for attribute sets. Iterates over every name-value pair in the given attribute set. The result of the callback function is often called `acc` for accumulator. It is passed between callbacks from left to right and the final `acc` is the return value of `foldlAttrs`. Attention: - There is a completely different function - `lib.foldAttrs` - which has nothing to do with this function, despite the similar name. - - Example: - foldlAttrs - (acc: name: value: { - sum = acc.sum + value; - names = acc.names ++ [name]; - }) - { sum = 0; names = []; } - { - foo = 1; - bar = 10; - } - -> - { - sum = 11; - names = ["bar" "foo"]; - } - - foldlAttrs - (throw "function not needed") - 123 - {}; - -> - 123 - - foldlAttrs - (acc: _: _: acc) - 3 - { z = throw "value not needed"; a = throw "value not needed"; }; - -> - 3 - - The accumulator doesn't have to be an attrset. - It can be as simple as a number or string. - - foldlAttrs - (acc: _: v: acc * 10 + v) - 1 - { z = 1; a = 2; }; - -> - 121 - - Type: - foldlAttrs :: ( a -> String -> b -> a ) -> a -> { ... :: b } -> a + + There is a completely different function `lib.foldAttrs` + which has nothing to do with this function, despite the similar name. + + + # Inputs + + `f` + + : 1\. Function argument + + `init` + + : 2\. Function argument + + `set` + + : 3\. Function argument + + # Type + + ``` + foldlAttrs :: ( a -> String -> b -> a ) -> a -> { ... :: b } -> a + ``` + + # Examples + :::{.example} + ## `lib.attrsets.foldlAttrs` usage example + + ```nix + foldlAttrs + (acc: name: value: { + sum = acc.sum + value; + names = acc.names ++ [name]; + }) + { sum = 0; names = []; } + { + foo = 1; + bar = 10; + } + -> + { + sum = 11; + names = ["bar" "foo"]; + } + + foldlAttrs + (throw "function not needed") + 123 + {}; + -> + 123 + + foldlAttrs + (acc: _: _: acc) + 3 + { z = throw "value not needed"; a = throw "value not needed"; }; + -> + 3 + + The accumulator doesn't have to be an attrset. + It can be as simple as a number or string. + + foldlAttrs + (acc: _: v: acc * 10 + v) + 1 + { z = 1; a = 2; }; + -> + 121 + ``` + + ::: */ foldlAttrs = f: init: set: foldl' @@ -505,22 +779,44 @@ rec { init (attrNames set); - /* Apply fold functions to values grouped by key. + /** + Apply fold functions to values grouped by key. + + + # Inputs + + `op` + + : A function, given a value and a collector combines the two. + + `nul` + + : The starting value. + + `list_of_attrs` + + : A list of attribute sets to fold together by key. + + # Type + + ``` + foldAttrs :: (Any -> Any -> Any) -> Any -> [AttrSets] -> Any + ``` - Example: - foldAttrs (item: acc: [item] ++ acc) [] [{ a = 2; } { a = 3; }] - => { a = [ 2 3 ]; } + # Examples + :::{.example} + ## `lib.attrsets.foldAttrs` usage example - Type: - foldAttrs :: (Any -> Any -> Any) -> Any -> [AttrSets] -> Any + ```nix + foldAttrs (item: acc: [item] ++ acc) [] [{ a = 2; } { a = 3; }] + => { a = [ 2 3 ]; } + ``` + ::: */ foldAttrs = - # A function, given a value and a collector combines the two. op: - # The starting value. nul: - # A list of attribute sets to fold together by key. list_of_attrs: foldr (n: a: foldr (name: o: @@ -529,26 +825,46 @@ rec { ) {} list_of_attrs; - /* Recursively collect sets that verify a given predicate named `pred` - from the set `attrs`. The recursion is stopped when the predicate is - verified. + /** + Recursively collect sets that verify a given predicate named `pred` + from the set `attrs`. The recursion is stopped when the predicate is + verified. + - Example: - collect isList { a = { b = ["b"]; }; c = [1]; } - => [["b"] [1]] + # Inputs - collect (x: x ? outPath) - { a = { outPath = "a/"; }; b = { outPath = "b/"; }; } - => [{ outPath = "a/"; } { outPath = "b/"; }] + `pred` + + : Given an attribute's value, determine if recursion should stop. + + `attrs` + + : The attribute set to recursively collect. + + # Type - Type: - collect :: (AttrSet -> Bool) -> AttrSet -> [x] + ``` + collect :: (AttrSet -> Bool) -> AttrSet -> [x] + ``` + + # Examples + :::{.example} + ## `lib.attrsets.collect` usage example + + ```nix + collect isList { a = { b = ["b"]; }; c = [1]; } + => [["b"] [1]] + + collect (x: x ? outPath) + { a = { outPath = "a/"; }; b = { outPath = "b/"; }; } + => [{ outPath = "a/"; } { outPath = "b/"; }] + ``` + + ::: */ collect = - # Given an attribute's value, determine if recursion should stop. - pred: - # The attribute set to recursively collect. - attrs: + pred: + attrs: if pred attrs then [ attrs ] else if isAttrs attrs then @@ -556,21 +872,39 @@ rec { else []; - /* Return the cartesian product of attribute set value combinations. - - Example: - cartesianProductOfSets { a = [ 1 2 ]; b = [ 10 20 ]; } - => [ - { a = 1; b = 10; } - { a = 1; b = 20; } - { a = 2; b = 10; } - { a = 2; b = 20; } - ] - Type: - cartesianProductOfSets :: AttrSet -> [AttrSet] + /** + Return the cartesian product of attribute set value combinations. + + + # Inputs + + `attrsOfLists` + + : Attribute set with attributes that are lists of values + + # Type + + ``` + cartesianProductOfSets :: AttrSet -> [AttrSet] + ``` + + # Examples + :::{.example} + ## `lib.attrsets.cartesianProductOfSets` usage example + + ```nix + cartesianProductOfSets { a = [ 1 2 ]; b = [ 10 20 ]; } + => [ + { a = 1; b = 10; } + { a = 1; b = 20; } + { a = 2; b = 10; } + { a = 2; b = 20; } + ] + ``` + + ::: */ cartesianProductOfSets = - # Attribute set with attributes that are lists of values attrsOfLists: foldl' (listOfAttrs: attrName: concatMap (attrs: @@ -579,76 +913,155 @@ rec { ) [{}] (attrNames attrsOfLists); - /* Utility function that creates a `{name, value}` pair as expected by `builtins.listToAttrs`. + /** + Utility function that creates a `{name, value}` pair as expected by `builtins.listToAttrs`. + + + # Inputs - Example: - nameValuePair "some" 6 - => { name = "some"; value = 6; } + `name` - Type: - nameValuePair :: String -> Any -> { name :: String; value :: Any; } + : Attribute name + + `value` + + : Attribute value + + # Type + + ``` + nameValuePair :: String -> Any -> { name :: String; value :: Any; } + ``` + + # Examples + :::{.example} + ## `lib.attrsets.nameValuePair` usage example + + ```nix + nameValuePair "some" 6 + => { name = "some"; value = 6; } + ``` + + ::: */ nameValuePair = - # Attribute name name: - # Attribute value value: { inherit name value; }; - /* Apply a function to each element in an attribute set, creating a new attribute set. + /** + Apply a function to each element in an attribute set, creating a new attribute set. + + # Inputs + + `f` - Example: - mapAttrs (name: value: name + "-" + value) - { x = "foo"; y = "bar"; } - => { x = "x-foo"; y = "y-bar"; } + : A function that takes an attribute name and its value, and returns the new value for the attribute. - Type: - mapAttrs :: (String -> Any -> Any) -> AttrSet -> AttrSet + `attrset` + + : The attribute set to iterate through. + + # Type + + ``` + mapAttrs :: (String -> Any -> Any) -> AttrSet -> AttrSet + ``` + + # Examples + :::{.example} + ## `lib.attrsets.mapAttrs` usage example + + ```nix + mapAttrs (name: value: name + "-" + value) + { x = "foo"; y = "bar"; } + => { x = "x-foo"; y = "y-bar"; } + ``` + + ::: */ mapAttrs = builtins.mapAttrs; - /* Like `mapAttrs`, but allows the name of each attribute to be - changed in addition to the value. The applied function should - return both the new name and value as a `nameValuePair`. + /** + Like `mapAttrs`, but allows the name of each attribute to be + changed in addition to the value. The applied function should + return both the new name and value as a `nameValuePair`. + + + # Inputs - Example: - mapAttrs' (name: value: nameValuePair ("foo_" + name) ("bar-" + value)) - { x = "a"; y = "b"; } - => { foo_x = "bar-a"; foo_y = "bar-b"; } + `f` - Type: - mapAttrs' :: (String -> Any -> { name :: String; value :: Any; }) -> AttrSet -> AttrSet + : A function, given an attribute's name and value, returns a new `nameValuePair`. + + `set` + + : Attribute set to map over. + + # Type + + ``` + mapAttrs' :: (String -> Any -> { name :: String; value :: Any; }) -> AttrSet -> AttrSet + ``` + + # Examples + :::{.example} + ## `lib.attrsets.mapAttrs'` usage example + + ```nix + mapAttrs' (name: value: nameValuePair ("foo_" + name) ("bar-" + value)) + { x = "a"; y = "b"; } + => { foo_x = "bar-a"; foo_y = "bar-b"; } + ``` + + ::: */ mapAttrs' = - # A function, given an attribute's name and value, returns a new `nameValuePair`. f: - # Attribute set to map over. set: listToAttrs (map (attr: f attr set.${attr}) (attrNames set)); - /* Call a function for each attribute in the given set and return - the result in a list. + /** + Call a function for each attribute in the given set and return + the result in a list. + + # Inputs + + `f` - Example: - mapAttrsToList (name: value: name + value) - { x = "a"; y = "b"; } - => [ "xa" "yb" ] + : A function, given an attribute's name and value, returns a new value. - Type: - mapAttrsToList :: (String -> a -> b) -> AttrSet -> [b] + `attrs` + : Attribute set to map over. + + # Type + + ``` + mapAttrsToList :: (String -> a -> b) -> AttrSet -> [b] + ``` + + # Examples + :::{.example} + ## `lib.attrsets.mapAttrsToList` usage example + + ```nix + mapAttrsToList (name: value: name + value) + { x = "a"; y = "b"; } + => [ "xa" "yb" ] + ``` + + ::: */ mapAttrsToList = - # A function, given an attribute's name and value, returns a new value. f: - # Attribute set to map over. attrs: map (name: f name attrs.${name}) (attrNames attrs); - /* + /** Deconstruct an attrset to a list of name-value pairs as expected by [`builtins.listToAttrs`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-listToAttrs). Each element of the resulting list is an attribute set with these attributes: - `name` (string): The name of the attribute @@ -668,13 +1081,28 @@ rec { This is because the `listToAttrs` removes duplicate names and doesn't preserve the order of the list. ::: - Example: - attrsToList { foo = 1; bar = "asdf"; } - => [ { name = "bar"; value = "asdf"; } { name = "foo"; value = 1; } ] + # Inputs + + `set` - Type: - attrsToList :: AttrSet -> [ { name :: String; value :: Any; } ] + : The attribute set to deconstruct. + + # Type + ``` + attrsToList :: AttrSet -> [ { name :: String; value :: Any; } ] + ``` + + # Examples + :::{.example} + ## `lib.attrsets.attrsToList` usage example + + ```nix + attrsToList { foo = 1; bar = "asdf"; } + => [ { name = "bar"; value = "asdf"; } { name = "foo"; value = 1; } ] + ``` + + ::: */ attrsToList = mapAttrsToList nameValuePair; @@ -705,9 +1133,7 @@ rec { ``` */ mapAttrsRecursive = - # A function that, given an attribute path as a list of strings and the corresponding attribute value, returns a new value. f: - # Attribute set to recursively map over. set: mapAttrsRecursiveCond (as: true) f set; @@ -736,12 +1162,8 @@ rec { ``` */ mapAttrsRecursiveCond = - # A function that, given the attribute set the recursion is currently at, determines if to recurse deeper into that attribute set. cond: - # A function that, given an attribute path as a list of strings and the corresponding attribute value, returns a new value. - # The attribute value is either an attribute set for which `cond` returns false, or something other than an attribute set. f: - # Attribute set to recursively map over. set: let recurse = path: @@ -754,48 +1176,95 @@ rec { recurse [ ] set; - /* Generate an attribute set by mapping a function over a list of - attribute names. + /** + Generate an attribute set by mapping a function over a list of + attribute names. + + + # Inputs + + `names` + + : Names of values in the resulting attribute set. + + `f` + + : A function, given the name of the attribute, returns the attribute's value. + + # Type + + ``` + genAttrs :: [ String ] -> (String -> Any) -> AttrSet + ``` + + # Examples + :::{.example} + ## `lib.attrsets.genAttrs` usage example - Example: - genAttrs [ "foo" "bar" ] (name: "x_" + name) - => { foo = "x_foo"; bar = "x_bar"; } + ```nix + genAttrs [ "foo" "bar" ] (name: "x_" + name) + => { foo = "x_foo"; bar = "x_bar"; } + ``` - Type: - genAttrs :: [ String ] -> (String -> Any) -> AttrSet + ::: */ genAttrs = - # Names of values in the resulting attribute set. names: - # A function, given the name of the attribute, returns the attribute's value. f: listToAttrs (map (n: nameValuePair n (f n)) names); - /* Check whether the argument is a derivation. Any set with - `{ type = "derivation"; }` counts as a derivation. + /** + Check whether the argument is a derivation. Any set with + `{ type = "derivation"; }` counts as a derivation. + - Example: - nixpkgs = import <nixpkgs> {} - isDerivation nixpkgs.ruby - => true - isDerivation "foobar" - => false + # Inputs - Type: - isDerivation :: Any -> Bool + `value` + + : Value to check. + + # Type + + ``` + isDerivation :: Any -> Bool + ``` + + # Examples + :::{.example} + ## `lib.attrsets.isDerivation` usage example + + ```nix + nixpkgs = import <nixpkgs> {} + isDerivation nixpkgs.ruby + => true + isDerivation "foobar" + => false + ``` + + ::: */ isDerivation = - # Value to check. value: value.type or null == "derivation"; - /* Converts a store path to a fake derivation. + /** + Converts a store path to a fake derivation. + + + # Inputs + + `path` - Type: - toDerivation :: Path -> Derivation - */ + : A store path to convert to a derivation. + + # Type + + ``` + toDerivation :: Path -> Derivation + ``` + */ toDerivation = - # A store path to convert to a derivation. path: let path' = builtins.storePath path; @@ -810,42 +1279,85 @@ rec { in res; - /* If `cond` is true, return the attribute set `as`, - otherwise an empty attribute set. + /** + If `cond` is true, return the attribute set `as`, + otherwise an empty attribute set. + + + # Inputs + + `cond` - Example: - optionalAttrs (true) { my = "set"; } - => { my = "set"; } - optionalAttrs (false) { my = "set"; } - => { } + : Condition under which the `as` attribute set is returned. + + `as` + + : The attribute set to return if `cond` is `true`. + + # Type + + ``` + optionalAttrs :: Bool -> AttrSet -> AttrSet + ``` + + # Examples + :::{.example} + ## `lib.attrsets.optionalAttrs` usage example + + ```nix + optionalAttrs (true) { my = "set"; } + => { my = "set"; } + optionalAttrs (false) { my = "set"; } + => { } + ``` - Type: - optionalAttrs :: Bool -> AttrSet -> AttrSet + ::: */ optionalAttrs = - # Condition under which the `as` attribute set is returned. cond: - # The attribute set to return if `cond` is `true`. as: if cond then as else {}; - /* Merge sets of attributes and use the function `f` to merge attributes - values. + /** + Merge sets of attributes and use the function `f` to merge attributes + values. + + + # Inputs + + `names` - Example: - zipAttrsWithNames ["a"] (name: vs: vs) [{a = "x";} {a = "y"; b = "z";}] - => { a = ["x" "y"]; } + : List of attribute names to zip. - Type: - zipAttrsWithNames :: [ String ] -> (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet + `f` + + : A function, accepts an attribute name, all the values, and returns a combined value. + + `sets` + + : List of values from the list of attribute sets. + + # Type + + ``` + zipAttrsWithNames :: [ String ] -> (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet + ``` + + # Examples + :::{.example} + ## `lib.attrsets.zipAttrsWithNames` usage example + + ```nix + zipAttrsWithNames ["a"] (name: vs: vs) [{a = "x";} {a = "y"; b = "z";}] + => { a = ["x" "y"]; } + ``` + + ::: */ zipAttrsWithNames = - # List of attribute names to zip. names: - # A function, accepts an attribute name, all the values, and returns a combined value. f: - # List of values from the list of attribute sets. sets: listToAttrs (map (name: { inherit name; @@ -853,52 +1365,91 @@ rec { }) names); - /* Merge sets of attributes and use the function f to merge attribute values. - Like `lib.attrsets.zipAttrsWithNames` with all key names are passed for `names`. + /** + Merge sets of attributes and use the function f to merge attribute values. + Like `lib.attrsets.zipAttrsWithNames` with all key names are passed for `names`. - Implementation note: Common names appear multiple times in the list of - names, hopefully this does not affect the system because the maximal - laziness avoid computing twice the same expression and `listToAttrs` does - not care about duplicated attribute names. + Implementation note: Common names appear multiple times in the list of + names, hopefully this does not affect the system because the maximal + laziness avoid computing twice the same expression and `listToAttrs` does + not care about duplicated attribute names. - Example: - zipAttrsWith (name: values: values) [{a = "x";} {a = "y"; b = "z";}] - => { a = ["x" "y"]; b = ["z"]; } + # Type + + ``` + zipAttrsWith :: (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet + ``` + + # Examples + :::{.example} + ## `lib.attrsets.zipAttrsWith` usage example - Type: - zipAttrsWith :: (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet + ```nix + zipAttrsWith (name: values: values) [{a = "x";} {a = "y"; b = "z";}] + => { a = ["x" "y"]; b = ["z"]; } + ``` + + ::: */ zipAttrsWith = builtins.zipAttrsWith or (f: sets: zipAttrsWithNames (concatMap attrNames sets) f sets); - /* Merge sets of attributes and combine each attribute value in to a list. + /** + Merge sets of attributes and combine each attribute value in to a list. + + Like `lib.attrsets.zipAttrsWith` with `(name: values: values)` as the function. + + # Type + + ``` + zipAttrs :: [ AttrSet ] -> AttrSet + ``` - Like `lib.attrsets.zipAttrsWith` with `(name: values: values)` as the function. + # Examples + :::{.example} + ## `lib.attrsets.zipAttrs` usage example - Example: - zipAttrs [{a = "x";} {a = "y"; b = "z";}] - => { a = ["x" "y"]; b = ["z"]; } + ```nix + zipAttrs [{a = "x";} {a = "y"; b = "z";}] + => { a = ["x" "y"]; b = ["z"]; } + ``` - Type: - zipAttrs :: [ AttrSet ] -> AttrSet + ::: */ zipAttrs = zipAttrsWith (name: values: values); - /* + /** Merge a list of attribute sets together using the `//` operator. In case of duplicate attributes, values from later list elements take precedence over earlier ones. The result is the same as `foldl mergeAttrs { }`, but the performance is better for large inputs. For n list elements, each with an attribute set containing m unique attributes, the complexity of this operation is O(nm log n). - Type: - mergeAttrsList :: [ Attrs ] -> Attrs - Example: - mergeAttrsList [ { a = 0; b = 1; } { c = 2; d = 3; } ] - => { a = 0; b = 1; c = 2; d = 3; } - mergeAttrsList [ { a = 0; } { a = 1; } ] - => { a = 1; } + # Inputs + + `list` + + : 1\. Function argument + + # Type + + ``` + mergeAttrsList :: [ Attrs ] -> Attrs + ``` + + # Examples + :::{.example} + ## `lib.attrsets.mergeAttrsList` usage example + + ```nix + mergeAttrsList [ { a = 0; b = 1; } { c = 2; d = 3; } ] + => { a = 0; b = 1; c = 2; d = 3; } + mergeAttrsList [ { a = 0; } { a = 1; } ] + => { a = 1; } + ``` + + ::: */ mergeAttrsList = list: let @@ -922,42 +1473,65 @@ rec { binaryMerge 0 (length list); - /* Does the same as the update operator '//' except that attributes are - merged until the given predicate is verified. The predicate should - accept 3 arguments which are the path to reach the attribute, a part of - the first attribute set and a part of the second attribute set. When - the predicate is satisfied, the value of the first attribute set is - replaced by the value of the second attribute set. - - Example: - recursiveUpdateUntil (path: l: r: path == ["foo"]) { - # first attribute set - foo.bar = 1; - foo.baz = 2; - bar = 3; - } { - #second attribute set - foo.bar = 1; - foo.quz = 2; - baz = 4; - } - - => { - foo.bar = 1; # 'foo.*' from the second set - foo.quz = 2; # - bar = 3; # 'bar' from the first set - baz = 4; # 'baz' from the second set - } - - Type: - recursiveUpdateUntil :: ( [ String ] -> AttrSet -> AttrSet -> Bool ) -> AttrSet -> AttrSet -> AttrSet + /** + Does the same as the update operator '//' except that attributes are + merged until the given predicate is verified. The predicate should + accept 3 arguments which are the path to reach the attribute, a part of + the first attribute set and a part of the second attribute set. When + the predicate is satisfied, the value of the first attribute set is + replaced by the value of the second attribute set. + + + # Inputs + + `pred` + + : Predicate, taking the path to the current attribute as a list of strings for attribute names, and the two values at that path from the original arguments. + + `lhs` + + : Left attribute set of the merge. + + `rhs` + + : Right attribute set of the merge. + + # Type + + ``` + recursiveUpdateUntil :: ( [ String ] -> AttrSet -> AttrSet -> Bool ) -> AttrSet -> AttrSet -> AttrSet + ``` + + # Examples + :::{.example} + ## `lib.attrsets.recursiveUpdateUntil` usage example + + ```nix + recursiveUpdateUntil (path: l: r: path == ["foo"]) { + # first attribute set + foo.bar = 1; + foo.baz = 2; + bar = 3; + } { + #second attribute set + foo.bar = 1; + foo.quz = 2; + baz = 4; + } + + => { + foo.bar = 1; # 'foo.*' from the second set + foo.quz = 2; # + bar = 3; # 'bar' from the first set + baz = 4; # 'baz' from the second set + } + ``` + + ::: */ recursiveUpdateUntil = - # Predicate, taking the path to the current attribute as a list of strings for attribute names, and the two values at that path from the original arguments. pred: - # Left attribute set of the merge. lhs: - # Right attribute set of the merge. rhs: let f = attrPath: zipAttrsWith (n: values: @@ -971,51 +1545,90 @@ rec { in f [] [rhs lhs]; - /* A recursive variant of the update operator ‘//’. The recursion - stops when one of the attribute values is not an attribute set, - in which case the right hand side value takes precedence over the - left hand side value. + /** + A recursive variant of the update operator ‘//’. The recursion + stops when one of the attribute values is not an attribute set, + in which case the right hand side value takes precedence over the + left hand side value. + + + # Inputs + + `lhs` + + : Left attribute set of the merge. + + `rhs` + + : Right attribute set of the merge. + + # Type + + ``` + recursiveUpdate :: AttrSet -> AttrSet -> AttrSet + ``` - Example: - recursiveUpdate { - boot.loader.grub.enable = true; - boot.loader.grub.device = "/dev/hda"; - } { - boot.loader.grub.device = ""; - } + # Examples + :::{.example} + ## `lib.attrsets.recursiveUpdate` usage example - returns: { - boot.loader.grub.enable = true; - boot.loader.grub.device = ""; - } + ```nix + recursiveUpdate { + boot.loader.grub.enable = true; + boot.loader.grub.device = "/dev/hda"; + } { + boot.loader.grub.device = ""; + } + + returns: { + boot.loader.grub.enable = true; + boot.loader.grub.device = ""; + } + ``` - Type: - recursiveUpdate :: AttrSet -> AttrSet -> AttrSet + ::: */ recursiveUpdate = - # Left attribute set of the merge. lhs: - # Right attribute set of the merge. rhs: recursiveUpdateUntil (path: lhs: rhs: !(isAttrs lhs && isAttrs rhs)) lhs rhs; - /* + /** Recurse into every attribute set of the first argument and check that: - Each attribute path also exists in the second argument. - If the attribute's value is not a nested attribute set, it must have the same value in the right argument. - Example: - matchAttrs { cpu = {}; } { cpu = { bits = 64; }; } - => true - Type: - matchAttrs :: AttrSet -> AttrSet -> Bool + # Inputs + + `pattern` + + : Attribute set structure to match + + `attrs` + + : Attribute set to check + + # Type + + ``` + matchAttrs :: AttrSet -> AttrSet -> Bool + ``` + + # Examples + :::{.example} + ## `lib.attrsets.matchAttrs` usage example + + ```nix + matchAttrs { cpu = {}; } { cpu = { bits = 64; }; } + => true + ``` + + ::: */ matchAttrs = - # Attribute set structure to match pattern: - # Attribute set to check attrs: assert isAttrs pattern; all @@ -1034,161 +1647,340 @@ rec { ) (attrNames pattern); - /* Override only the attributes that are already present in the old set + /** + Override only the attributes that are already present in the old set useful for deep-overriding. - Example: - overrideExisting {} { a = 1; } - => {} - overrideExisting { b = 2; } { a = 1; } - => { b = 2; } - overrideExisting { a = 3; b = 2; } { a = 1; } - => { a = 1; b = 2; } - Type: - overrideExisting :: AttrSet -> AttrSet -> AttrSet + # Inputs + + `old` + + : Original attribute set + + `new` + + : Attribute set with attributes to override in `old`. + + # Type + + ``` + overrideExisting :: AttrSet -> AttrSet -> AttrSet + ``` + + # Examples + :::{.example} + ## `lib.attrsets.overrideExisting` usage example + + ```nix + overrideExisting {} { a = 1; } + => {} + overrideExisting { b = 2; } { a = 1; } + => { b = 2; } + overrideExisting { a = 3; b = 2; } { a = 1; } + => { a = 1; b = 2; } + ``` + + ::: */ overrideExisting = - # Original attribute set old: - # Attribute set with attributes to override in `old`. new: mapAttrs (name: value: new.${name} or value) old; - /* Turns a list of strings into a human-readable description of those + /** + Turns a list of strings into a human-readable description of those strings represented as an attribute path. The result of this function is not intended to be machine-readable. Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`. - Example: - showAttrPath [ "foo" "10" "bar" ] - => "foo.\"10\".bar" - showAttrPath [] - => "<root attribute path>" - Type: - showAttrPath :: [String] -> String + # Inputs + + `path` + + : Attribute path to render to a string + + # Type + + ``` + showAttrPath :: [String] -> String + ``` + + # Examples + :::{.example} + ## `lib.attrsets.showAttrPath` usage example + + ```nix + showAttrPath [ "foo" "10" "bar" ] + => "foo.\"10\".bar" + showAttrPath [] + => "<root attribute path>" + ``` + + ::: */ showAttrPath = - # Attribute path to render to a string path: if path == [] then "<root attribute path>" else concatMapStringsSep "." escapeNixIdentifier path; - /* Get a package output. - If no output is found, fallback to `.out` and then to the default. + /** + Get a package output. + If no output is found, fallback to `.out` and then to the default. + + + # Inputs + + `output` - Example: - getOutput "dev" pkgs.openssl - => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev" + : 1\. Function argument - Type: - getOutput :: String -> Derivation -> String + `pkg` + + : 2\. Function argument + + # Type + + ``` + getOutput :: String -> Derivation -> String + ``` + + # Examples + :::{.example} + ## `lib.attrsets.getOutput` usage example + + ```nix + getOutput "dev" pkgs.openssl + => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev" + ``` + + ::: */ getOutput = output: pkg: if ! pkg ? outputSpecified || ! pkg.outputSpecified then pkg.${output} or pkg.out or pkg else pkg; - /* Get a package's `bin` output. - If the output does not exist, fallback to `.out` and then to the default. + /** + Get a package's `bin` output. + If the output does not exist, fallback to `.out` and then to the default. + + # Inputs + + `pkg` - Example: - getBin pkgs.openssl - => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r" + : The package whose `bin` output will be retrieved. - Type: - getBin :: Derivation -> String + # Type + + ``` + getBin :: Derivation -> String + ``` + + # Examples + :::{.example} + ## `lib.attrsets.getBin` usage example + + ```nix + getBin pkgs.openssl + => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r" + ``` + + ::: */ getBin = getOutput "bin"; - /* Get a package's `lib` output. - If the output does not exist, fallback to `.out` and then to the default. + /** + Get a package's `lib` output. + If the output does not exist, fallback to `.out` and then to the default. + + # Inputs + + `pkg` - Example: - getLib pkgs.openssl - => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-lib" + : The package whose `lib` output will be retrieved. - Type: - getLib :: Derivation -> String + # Type + + ``` + getLib :: Derivation -> String + ``` + + # Examples + :::{.example} + ## `lib.attrsets.getLib` usage example + + ```nix + getLib pkgs.openssl + => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-lib" + ``` + + ::: */ getLib = getOutput "lib"; - /* Get a package's `dev` output. - If the output does not exist, fallback to `.out` and then to the default. + /** + Get a package's `dev` output. + If the output does not exist, fallback to `.out` and then to the default. + + # Inputs + + `pkg` - Example: - getDev pkgs.openssl - => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev" + : The package whose `dev` output will be retrieved. + + # Type + + ``` + getDev :: Derivation -> String + ``` - Type: - getDev :: Derivation -> String + # Examples + :::{.example} + ## `lib.attrsets.getDev` usage example + + ```nix + getDev pkgs.openssl + => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev" + ``` + + ::: */ getDev = getOutput "dev"; - /* Get a package's `man` output. - If the output does not exist, fallback to `.out` and then to the default. + /** + Get a package's `man` output. + If the output does not exist, fallback to `.out` and then to the default. + + # Inputs + + `pkg` + + : The package whose `man` output will be retrieved. + + # Type + + ``` + getMan :: Derivation -> String + ``` + + # Examples + :::{.example} + ## `lib.attrsets.getMan` usage example - Example: - getMan pkgs.openssl - => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-man" + ```nix + getMan pkgs.openssl + => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-man" + ``` - Type: - getMan :: Derivation -> String + ::: */ getMan = getOutput "man"; - /* Pick the outputs of packages to place in `buildInputs` + /** + Pick the outputs of packages to place in `buildInputs` + + # Inputs - Type: chooseDevOutputs :: [Derivation] -> [String] + `pkgs` + : List of packages. + + # Type + + ``` + chooseDevOutputs :: [Derivation] -> [String] + ``` */ chooseDevOutputs = builtins.map getDev; - /* Make various Nix tools consider the contents of the resulting - attribute set when looking for what to build, find, etc. + /** + Make various Nix tools consider the contents of the resulting + attribute set when looking for what to build, find, etc. - This function only affects a single attribute set; it does not - apply itself recursively for nested attribute sets. + This function only affects a single attribute set; it does not + apply itself recursively for nested attribute sets. - Example: - { pkgs ? import <nixpkgs> {} }: - { - myTools = pkgs.lib.recurseIntoAttrs { - inherit (pkgs) hello figlet; - }; - } - Type: - recurseIntoAttrs :: AttrSet -> AttrSet + # Inputs + + `attrs` + + : An attribute set to scan for derivations. + + # Type - */ + ``` + recurseIntoAttrs :: AttrSet -> AttrSet + ``` + + # Examples + :::{.example} + ## `lib.attrsets.recurseIntoAttrs` usage example + + ```nix + { pkgs ? import <nixpkgs> {} }: + { + myTools = pkgs.lib.recurseIntoAttrs { + inherit (pkgs) hello figlet; + }; + } + ``` + + ::: + */ recurseIntoAttrs = - # An attribute set to scan for derivations. attrs: attrs // { recurseForDerivations = true; }; - /* Undo the effect of recurseIntoAttrs. + /** + Undo the effect of recurseIntoAttrs. - Type: - dontRecurseIntoAttrs :: AttrSet -> AttrSet - */ + + # Inputs + + `attrs` + + : An attribute set to not scan for derivations. + + # Type + + ``` + dontRecurseIntoAttrs :: AttrSet -> AttrSet + ``` + */ dontRecurseIntoAttrs = - # An attribute set to not scan for derivations. attrs: attrs // { recurseForDerivations = false; }; - /* `unionOfDisjoint x y` is equal to `x // y // z` where the - attrnames in `z` are the intersection of the attrnames in `x` and - `y`, and all values `assert` with an error message. This - operator is commutative, unlike (//). + /** + `unionOfDisjoint x y` is equal to `x // y // z` where the + attrnames in `z` are the intersection of the attrnames in `x` and + `y`, and all values `assert` with an error message. This + operator is commutative, unlike (//). + + + # Inputs + + `x` + + : 1\. Function argument + + `y` - Type: unionOfDisjoint :: AttrSet -> AttrSet -> AttrSet + : 2\. Function argument + + # Type + + ``` + unionOfDisjoint :: AttrSet -> AttrSet -> AttrSet + ``` */ unionOfDisjoint = x: y: let diff --git a/nixpkgs/lib/customisation.nix b/nixpkgs/lib/customisation.nix index 7be412bac353..66638b63342a 100644 --- a/nixpkgs/lib/customisation.nix +++ b/nixpkgs/lib/customisation.nix @@ -306,18 +306,129 @@ rec { in if drv == null then null else deepSeq drv' drv'; - /* Make a set of packages with a common scope. All packages called - with the provided `callPackage` will be evaluated with the same - arguments. Any package in the set may depend on any other. The - `overrideScope'` function allows subsequent modification of the package - set in a consistent way, i.e. all packages in the set will be - called with the overridden packages. The package sets may be - hierarchical: the packages in the set are called with the scope - provided by `newScope` and the set provides a `newScope` attribute - which can form the parent scope for later package sets. + /** + Make an attribute set (a "scope") from functions that take arguments from that same attribute set. + See [](#ex-makeScope) for how to use it. - Type: - makeScope :: (AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a) -> (AttrSet -> AttrSet) -> AttrSet + # Inputs + + 1. `newScope` (`AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a`) + + A function that takes an attribute set `attrs` and returns what ends up as `callPackage` in the output. + + Typical values are `callPackageWith` or the output attribute `newScope`. + + 2. `f` (`AttrSet -> AttrSet`) + + A function that takes an attribute set as returned by `makeScope newScope f` (a "scope") and returns any attribute set. + + This function is used to compute the fixpoint of the resulting scope using `callPackage`. + Its argument is the lazily evaluated reference to the value of that fixpoint, and is typically called `self` or `final`. + + See [](#ex-makeScope) for how to use it. + See [](#sec-functions-library-fixedPoints) for details on fixpoint computation. + + # Output + + `makeScope` returns an attribute set of a form called `scope`, which also contains the final attributes produced by `f`: + + ``` + scope :: { + callPackage :: ((AttrSet -> a) | Path) -> AttrSet -> a + newScope = AttrSet -> scope + overrideScope = (scope -> scope -> AttrSet) -> scope + packages :: AttrSet -> AttrSet + } + ``` + + - `callPackage` (`((AttrSet -> a) | Path) -> AttrSet -> a`) + + A function that + + 1. Takes a function `p`, or a path to a Nix file that contains a function `p`, which takes an attribute set and returns value of arbitrary type `a`, + 2. Takes an attribute set `args` with explicit attributes to pass to `p`, + 3. Calls `f` with attributes from the original attribute set `attrs` passed to `newScope` updated with `args, i.e. `attrs // args`, if they match the attributes in the argument of `p`. + + All such functions `p` will be called with the same value for `attrs`. + + See [](#ex-makeScope-callPackage) for how to use it. + + - `newScope` (`AttrSet -> scope`) + + Takes an attribute set `attrs` and returns a scope that extends the original scope. + + - `overrideScope` (`(scope -> scope -> AttrSet) -> scope`) + + Takes a function `g` of the form `final: prev: { # attributes }` to act as an overlay on `f`, and returns a new scope with values determined by `extends g f`. + See [](https://nixos.org/manual/nixpkgs/unstable/#function-library-lib.fixedPoints.extends) for details. + + This allows subsequent modification of the final attribute set in a consistent way, i.e. all functions `p` invoked with `callPackage` will be called with the modified values. + + - `packages` (`AttrSet -> AttrSet`) + + The value of the argument `f` to `makeScope`. + + - final attributes + + The final values returned by `f`. + + # Examples + + :::{#ex-makeScope .example} + # Create an interdependent package set on top of `pkgs` + + The functions in `foo.nix` and `bar.nix` can depend on each other, in the sense that `foo.nix` can contain a function that expects `bar` as an attribute in its argument. + + ```nix + let + pkgs = import <nixpkgs> { }; + in + pkgs.lib.makeScope pkgs.newScope (self: { + foo = self.callPackage ./foo.nix { }; + bar = self.callPackage ./bar.nix { }; + }) + ``` + + evaluates to + + ```nix + { + callPackage = «lambda»; + newScope = «lambda»; + overrideScope = «lambda»; + packages = «lambda»; + foo = «derivation»; + bar = «derivation»; + } + ``` + ::: + + :::{#ex-makeScope-callPackage .example} + # Using `callPackage` from a scope + + ```nix + let + pkgs = import <nixpkgs> { }; + inherit (pkgs) lib; + scope = lib.makeScope lib.callPackageWith (self: { a = 1; b = 2; }); + three = scope.callPackage ({ a, b }: a + b) { }; + four = scope.callPackage ({ a, b }: a + b) { a = 2; }; + in + [ three four ] + ``` + + evaluates to + + ```nix + [ 3 4 ] + ``` + ::: + + # Type + + ``` + makeScope :: (AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a) -> (AttrSet -> AttrSet) -> scope + ``` */ makeScope = newScope: f: let self = f self // { diff --git a/nixpkgs/lib/deprecated.nix b/nixpkgs/lib/deprecated.nix index ed14e04bbd68..b76622b5d842 100644 --- a/nixpkgs/lib/deprecated.nix +++ b/nixpkgs/lib/deprecated.nix @@ -1,14 +1,37 @@ { lib }: -let - inherit (builtins) head tail isList isAttrs isInt attrNames; - -in - -with lib.lists; -with lib.attrsets; -with lib.strings; -rec { +let + inherit (lib) + and + any + attrByPath + attrNames + compare + concat + concatMap + elem + filter + foldl + foldr + genericClosure + head + imap1 + init + isAttrs + isFunction + isInt + isList + lists + listToAttrs + mapAttrs + mergeAttrs + meta + nameValuePair + tail + toList + ; + + inherit (lib.attrsets) removeAttrs; # returns default if env var is not set maybeEnv = name: default: @@ -26,7 +49,7 @@ rec { base = (setAttrMerge "passthru" {} (f arg) ( z: z // { function = foldArgs merger f arg; - args = (lib.attrByPath ["passthru" "args"] {} z) // x; + args = (attrByPath ["passthru" "args"] {} z) // x; } )); withStdOverrides = base // { override = base.passthru.function; @@ -77,11 +100,11 @@ rec { # Output : are reqs satisfied? It's asserted. checkReqs = attrSet: argList: condList: ( - foldr lib.and true + foldr and true (map (x: let name = (head x); in ((checkFlag attrSet name) -> - (foldr lib.and true + (foldr and true (map (y: let val=(getValue attrSet argList y); in (val!=null) && (val!=false)) (tail x))))) condList)); @@ -159,11 +182,11 @@ rec { closePropagationSlow = list: (uniqList {inputList = (innerClosePropagation [] list);}); - # This is an optimisation of lib.closePropagation which avoids the O(n^2) behavior + # This is an optimisation of closePropagation which avoids the O(n^2) behavior # Using a list of derivations, it generates the full closure of the propagatedXXXBuildInputs # The ordering / sorting / comparison is done based on the `outPath` # attribute of each derivation. - # On some benchmarks, it performs up to 15 times faster than lib.closePropagation. + # On some benchmarks, it performs up to 15 times faster than closePropagation. # See https://github.com/NixOS/nixpkgs/pull/194391 for details. closePropagationFast = list: builtins.map (x: x.val) (builtins.genericClosure { @@ -250,10 +273,10 @@ rec { # foldArgs, composedArgsAndFun or applyAndFun. Example: composableDerivation in all-packages.nix mergeAttrByFunc = x: y: let - mergeAttrBy2 = { mergeAttrBy = lib.mergeAttrs; } + mergeAttrBy2 = { mergeAttrBy = mergeAttrs; } // (maybeAttr "mergeAttrBy" {} x) // (maybeAttr "mergeAttrBy" {} y); in - foldr lib.mergeAttrs {} [ + foldr mergeAttrs {} [ x y (mapAttrs ( a: v: # merge special names using given functions if x ? ${a} @@ -273,9 +296,9 @@ rec { # sane defaults (same name as attr name so that inherit can be used) mergeAttrBy = # { buildInputs = concatList; [...]; passthru = mergeAttr; [..]; } - listToAttrs (map (n: nameValuePair n lib.concat) + listToAttrs (map (n: nameValuePair n concat) [ "nativeBuildInputs" "buildInputs" "propagatedBuildInputs" "configureFlags" "prePhases" "postAll" "patches" ]) - // listToAttrs (map (n: nameValuePair n lib.mergeAttrs) [ "passthru" "meta" "cfg" "flags" ]) + // listToAttrs (map (n: nameValuePair n mergeAttrs) [ "passthru" "meta" "cfg" "flags" ]) // listToAttrs (map (n: nameValuePair n (a: b: "${a}\n${b}") ) [ "preConfigure" "postInstall" ]) ; @@ -283,7 +306,7 @@ rec { if isAttrs x then if x ? outPath then "derivation" else "attrs" - else if lib.isFunction x then "function" + else if isFunction x then "function" else if isList x then "list" else if x == true then "bool" else if x == false then "bool" @@ -304,4 +327,47 @@ rec { fakeHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; fakeSha256 = "0000000000000000000000000000000000000000000000000000000000000000"; fakeSha512 = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + +in + +# Everything in this attrset is the public interface of the file. +{ + inherit + checkFlag + checkReqs + closePropagation + closePropagationFast + closePropagationSlow + condConcat + defaultMerge + defaultMergeArg + fakeHash + fakeSha256 + fakeSha512 + foldArgs + getValue + ifEnable + imap + innerClosePropagation + innerModifySumArgs + lazyGenericClosure + mapAttrsFlatten + maybeAttr + maybeAttrNullable + maybeEnv + mergeAttrBy + mergeAttrByFunc + mergeAttrsByFuncDefaults + mergeAttrsByFuncDefaultsClean + mergeAttrsConcatenateValues + mergeAttrsNoOverride + mergeAttrsWithFunc + modifySumArgs + nixType + nvs + setAttr + setAttrMerge + uniqList + uniqListExt + ; } diff --git a/nixpkgs/lib/generators.nix b/nixpkgs/lib/generators.nix index ed59654cc07e..5f42a98de709 100644 --- a/nixpkgs/lib/generators.nix +++ b/nixpkgs/lib/generators.nix @@ -14,15 +14,58 @@ * Documentation in the manual, #sec-generators */ { lib }: -with (lib).trivial; -let - libStr = lib.strings; - libAttr = lib.attrsets; - - inherit (lib) isFunction; -in -rec { +let + inherit (lib) + addErrorContext + assertMsg + attrNames + concatLists + concatMapStringsSep + concatStrings + concatStringsSep + const + elem + escape + filter + flatten + foldl + functionArgs # Note: not the builtin; considers `__functor` in attrsets. + gvariant + hasInfix + head + id + init + isAttrs + isBool + isDerivation + isFloat + isFunction # Note: not the builtin; considers `__functor` in attrsets. + isInt + isList + isPath + isString + last + length + mapAttrs + mapAttrsToList + optionals + recursiveUpdate + replaceStrings + reverseList + splitString + tail + toList + ; + + inherit (lib.strings) + escapeNixIdentifier + floatToString + match + split + toJSON + typeOf + ; ## -- HELPER FUNCTIONS & DEFAULTS -- @@ -30,13 +73,13 @@ rec { * The builtin `toString` function has some strange defaults, * suitable for bash scripts but not much else. */ - mkValueStringDefault = {}: v: with builtins; + mkValueStringDefault = {}: v: let err = t: v: abort ("generators.mkValueStringDefault: " + "${t} not supported: ${toPretty {} v}"); in if isInt v then toString v # convert derivations to store paths - else if lib.isDerivation v then toString v + else if isDerivation v then toString v # we default to not quoting strings else if isString v then v # isString returns "1", which is not a good default @@ -53,7 +96,7 @@ rec { # Floats currently can't be converted to precise strings, # condition warning on nix version once this isn't a problem anymore # See https://github.com/NixOS/nix/pull/3480 - else if isFloat v then libStr.floatToString v + else if isFloat v then floatToString v else err "this value is" (toString v); @@ -69,7 +112,7 @@ rec { mkKeyValueDefault = { mkValueString ? mkValueStringDefault {} }: sep: k: v: - "${libStr.escape [sep] k}${sep}${mkValueString v}"; + "${escape [sep] k}${sep}${mkValueString v}"; ## -- FILE FORMAT GENERATORS -- @@ -86,9 +129,9 @@ rec { }: let mkLine = k: v: indent + mkKeyValue k v + "\n"; mkLines = if listsAsDuplicateKeys - then k: v: map (mkLine k) (if lib.isList v then v else [v]) + then k: v: map (mkLine k) (if isList v then v else [v]) else k: v: [ (mkLine k v) ]; - in attrs: libStr.concatStrings (lib.concatLists (libAttr.mapAttrsToList mkLines attrs)); + in attrs: concatStrings (concatLists (mapAttrsToList mkLines attrs)); /* Generate an INI-style config file from an @@ -113,7 +156,7 @@ rec { */ toINI = { # apply transformations (e.g. escapes) to section names - mkSectionName ? (name: libStr.escape [ "[" "]" ] name), + mkSectionName ? (name: escape [ "[" "]" ] name), # format a setting line from key and value mkKeyValue ? mkKeyValueDefault {} "=", # allow lists as values for duplicate keys @@ -122,8 +165,8 @@ rec { let # map function to string for each key val mapAttrsToStringsSep = sep: mapFn: attrs: - libStr.concatStringsSep sep - (libAttr.mapAttrsToList mapFn attrs); + concatStringsSep sep + (mapAttrsToList mapFn attrs); mkSection = sectName: sectValues: '' [${mkSectionName sectName}] '' + toKeyValue { inherit mkKeyValue listsAsDuplicateKeys; } sectValues; @@ -164,7 +207,7 @@ rec { */ toINIWithGlobalSection = { # apply transformations (e.g. escapes) to section names - mkSectionName ? (name: libStr.escape [ "[" "]" ] name), + mkSectionName ? (name: escape [ "[" "]" ] name), # format a setting line from key and value mkKeyValue ? mkKeyValueDefault {} "=", # allow lists as values for duplicate keys @@ -195,12 +238,11 @@ rec { *> name = "edolstra" */ toGitINI = attrs: - with builtins; let mkSectionName = name: let - containsQuote = libStr.hasInfix ''"'' name; - sections = libStr.splitString "." name; + containsQuote = hasInfix ''"'' name; + sections = splitString "." name; section = head sections; subsections = tail sections; subsection = concatStringsSep "." subsections; @@ -220,19 +262,19 @@ rec { # generation for multiple ini values mkKeyValue = k: v: let mkKeyValue = mkKeyValueDefault { inherit mkValueString; } " = " k; - in concatStringsSep "\n" (map (kv: "\t" + mkKeyValue kv) (lib.toList v)); + in concatStringsSep "\n" (map (kv: "\t" + mkKeyValue kv) (toList v)); # converts { a.b.c = 5; } to { "a.b".c = 5; } for toINI gitFlattenAttrs = let recurse = path: value: - if isAttrs value && !lib.isDerivation value then - lib.mapAttrsToList (name: value: recurse ([ name ] ++ path) value) value + if isAttrs value && !isDerivation value then + mapAttrsToList (name: value: recurse ([ name ] ++ path) value) value else if length path > 1 then { - ${concatStringsSep "." (lib.reverseList (tail path))}.${head path} = value; + ${concatStringsSep "." (reverseList (tail path))}.${head path} = value; } else { ${head path} = value; }; - in attrs: lib.foldl lib.recursiveUpdate { } (lib.flatten (recurse [ ] attrs)); + in attrs: foldl recursiveUpdate { } (flatten (recurse [ ] attrs)); toINI_ = toINI { inherit mkKeyValue mkSectionName; }; in @@ -240,25 +282,12 @@ rec { # mkKeyValueDefault wrapper that handles dconf INI quirks. # The main differences of the format is that it requires strings to be quoted. - mkDconfKeyValue = mkKeyValueDefault { mkValueString = v: toString (lib.gvariant.mkValue v); } "="; + mkDconfKeyValue = mkKeyValueDefault { mkValueString = v: toString (gvariant.mkValue v); } "="; # Generates INI in dconf keyfile style. See https://help.gnome.org/admin/system-admin-guide/stable/dconf-keyfiles.html.en # for details. toDconfINI = toINI { mkKeyValue = mkDconfKeyValue; }; - /* Generates JSON from an arbitrary (non-function) value. - * For more information see the documentation of the builtin. - */ - toJSON = {}: builtins.toJSON; - - - /* YAML has been a strict superset of JSON since 1.2, so we - * use toJSON. Before it only had a few differences referring - * to implicit typing rules, so it should work with older - * parsers as well. - */ - toYAML = toJSON; - withRecursion = { /* If this option is not null, the given value will stop evaluating at a certain depth */ @@ -266,7 +295,7 @@ rec { /* If this option is true, an error will be thrown, if a certain given depth is exceeded */ , throwOnDepthLimit ? true }: - assert builtins.isInt depthLimit; + assert isInt depthLimit; let specialAttrs = [ "__functor" @@ -275,7 +304,7 @@ rec { "__pretty" ]; stepIntoAttr = evalNext: name: - if builtins.elem name specialAttrs + if elem name specialAttrs then id else evalNext; transform = depth: @@ -284,7 +313,7 @@ rec { then throw "Exceeded maximum eval-depth limit of ${toString depthLimit} while trying to evaluate with `generators.withRecursion'!" else const "<unevaluated>" else id; - mapAny = with builtins; depth: v: + mapAny = depth: v: let evalNext = x: mapAny (depth + 1) (transform (depth + 1) x); in @@ -311,9 +340,8 @@ rec { indent ? "" }: let - go = indent: v: with builtins; - let isPath = v: typeOf v == "path"; - introSpace = if multiline then "\n${indent} " else " "; + go = indent: v: + let introSpace = if multiline then "\n${indent} " else " "; outroSpace = if multiline then "\n${indent}" else " "; in if isInt v then toString v # toString loses precision on floats, so we use toJSON instead. This isn't perfect @@ -322,16 +350,16 @@ rec { else if isFloat v then builtins.toJSON v else if isString v then let - lines = filter (v: ! isList v) (builtins.split "\n" v); - escapeSingleline = libStr.escape [ "\\" "\"" "\${" ]; - escapeMultiline = libStr.replaceStrings [ "\${" "''" ] [ "''\${" "'''" ]; + lines = filter (v: ! isList v) (split "\n" v); + escapeSingleline = escape [ "\\" "\"" "\${" ]; + escapeMultiline = replaceStrings [ "\${" "''" ] [ "''\${" "'''" ]; singlelineResult = "\"" + concatStringsSep "\\n" (map escapeSingleline lines) + "\""; multilineResult = let escapedLines = map escapeMultiline lines; # The last line gets a special treatment: if it's empty, '' is on its own line at the "outer" # indentation level. Otherwise, '' is appended to the last line. - lastLine = lib.last escapedLines; - in "''" + introSpace + concatStringsSep introSpace (lib.init escapedLines) + lastLine = last escapedLines; + in "''" + introSpace + concatStringsSep introSpace (init escapedLines) + (if lastLine == "" then outroSpace else introSpace + lastLine) + "''"; in if multiline && length lines > 1 then multilineResult else singlelineResult @@ -342,11 +370,11 @@ rec { else if isList v then if v == [] then "[ ]" else "[" + introSpace - + libStr.concatMapStringsSep introSpace (go (indent + " ")) v + + concatMapStringsSep introSpace (go (indent + " ")) v + outroSpace + "]" else if isFunction v then - let fna = lib.functionArgs v; - showFnas = concatStringsSep ", " (libAttr.mapAttrsToList + let fna = functionArgs v; + showFnas = concatStringsSep ", " (mapAttrsToList (name: hasDefVal: if hasDefVal then name + "?" else name) fna); in if fna == {} then "<function>" @@ -359,10 +387,10 @@ rec { else if v ? type && v.type == "derivation" then "<derivation ${v.name or "???"}>" else "{" + introSpace - + libStr.concatStringsSep introSpace (libAttr.mapAttrsToList + + concatStringsSep introSpace (mapAttrsToList (name: value: - "${libStr.escapeNixIdentifier name} = ${ - builtins.addErrorContext "while evaluating an attribute `${name}`" + "${escapeNixIdentifier name} = ${ + addErrorContext "while evaluating an attribute `${name}`" (go (indent + " ") value) };") v) + outroSpace + "}" @@ -371,9 +399,7 @@ rec { # PLIST handling toPlist = {}: v: let - isFloat = builtins.isFloat or (x: false); - isPath = x: builtins.typeOf x == "path"; - expr = ind: x: with builtins; + expr = ind: x: if x == null then "" else if isBool x then bool ind x else if isInt x then int ind x else @@ -394,23 +420,23 @@ rec { indent = ind: expr "\t${ind}"; - item = ind: libStr.concatMapStringsSep "\n" (indent ind); + item = ind: concatMapStringsSep "\n" (indent ind); - list = ind: x: libStr.concatStringsSep "\n" [ + list = ind: x: concatStringsSep "\n" [ (literal ind "<array>") (item ind x) (literal ind "</array>") ]; - attrs = ind: x: libStr.concatStringsSep "\n" [ + attrs = ind: x: concatStringsSep "\n" [ (literal ind "<dict>") (attr ind x) (literal ind "</dict>") ]; attr = let attrFilter = name: value: name != "_module" && value != null; - in ind: x: libStr.concatStringsSep "\n" (lib.flatten (lib.mapAttrsToList - (name: value: lib.optionals (attrFilter name value) [ + in ind: x: concatStringsSep "\n" (flatten (mapAttrsToList + (name: value: optionals (attrFilter name value) [ (key "\t${ind}" name) (expr "\t${ind}" value) ]) x)); @@ -426,11 +452,10 @@ ${expr "" v} * the Natural type. */ toDhall = { }@args: v: - with builtins; - let concatItems = lib.strings.concatStringsSep ", "; + let concatItems = concatStringsSep ", "; in if isAttrs v then "{ ${ - concatItems (lib.attrsets.mapAttrsToList + concatItems (mapAttrsToList (key: value: "${key} = ${toDhall args value}") v) } }" else if isList v then @@ -444,7 +469,7 @@ ${expr "" v} else if v == null then abort "generators.toDhall: cannot convert a null to Dhall" else - builtins.toJSON v; + toJSON v; /* Translate a simple Nix expression to Lua representation with occasional @@ -488,7 +513,6 @@ ${expr "" v} /* Interpret as variable bindings */ asBindings ? false, }@args: v: - with builtins; let innerIndent = "${indent} "; introSpace = if multiline then "\n${innerIndent}" else " "; @@ -501,9 +525,9 @@ ${expr "" v} isLuaInline = { _type ? null, ... }: _type == "lua-inline"; generatedBindings = - assert lib.assertMsg (badVarNames == []) "Bad Lua var names: ${toPretty {} badVarNames}"; - libStr.concatStrings ( - lib.attrsets.mapAttrsToList (key: value: "${indent}${key} = ${toLua innerArgs value}\n") v + assert assertMsg (badVarNames == []) "Bad Lua var names: ${toPretty {} badVarNames}"; + concatStrings ( + mapAttrsToList (key: value: "${indent}${key} = ${toLua innerArgs value}\n") v ); # https://en.wikibooks.org/wiki/Lua_Programming/variable#Variable_names @@ -515,7 +539,7 @@ ${expr "" v} else if v == null then "nil" else if isInt v || isFloat v || isString v || isBool v then - builtins.toJSON v + toJSON v else if isList v then (if v == [ ] then "{}" else "{${introSpace}${concatItems (map (value: "${toLua innerArgs value}") v)}${outroSpace}}") @@ -525,11 +549,11 @@ ${expr "" v} "(${v.expr})" else if v == { } then "{}" - else if libAttr.isDerivation v then + else if isDerivation v then ''"${toString v}"'' else "{${introSpace}${concatItems ( - lib.attrsets.mapAttrsToList (key: value: "[${builtins.toJSON key}] = ${toLua innerArgs value}") v + mapAttrsToList (key: value: "[${toJSON key}] = ${toLua innerArgs value}") v )}${outroSpace}}" ) else @@ -542,4 +566,37 @@ ${expr "" v} mkLuaInline :: String -> AttrSet */ mkLuaInline = expr: { _type = "lua-inline"; inherit expr; }; + +in + +# Everything in this attrset is the public interface of the file. +{ + inherit + mkDconfKeyValue + mkKeyValueDefault + mkLuaInline + mkValueStringDefault + toDconfINI + toDhall + toGitINI + toINI + toINIWithGlobalSection + toKeyValue + toLua + toPlist + toPretty + withRecursion + ; + + /* Generates JSON from an arbitrary (non-function) value. + * For more information see the documentation of the builtin. + */ + toJSON = {}: toJSON; + + /* YAML has been a strict superset of JSON since 1.2, so we + * use toJSON. Before it only had a few differences referring + * to implicit typing rules, so it should work with older + * parsers as well. + */ + toYAML = {}: toJSON; } diff --git a/nixpkgs/lib/kernel.nix b/nixpkgs/lib/kernel.nix index 33da9663a8ed..7391f9e5d079 100644 --- a/nixpkgs/lib/kernel.nix +++ b/nixpkgs/lib/kernel.nix @@ -1,6 +1,8 @@ { lib }: -with lib; +let + inherit (lib) mkIf versionAtLeast versionOlder; +in { diff --git a/nixpkgs/lib/licenses.nix b/nixpkgs/lib/licenses.nix index 30ca31ff71f2..4cda7e5c01a3 100644 --- a/nixpkgs/lib/licenses.nix +++ b/nixpkgs/lib/licenses.nix @@ -599,6 +599,11 @@ in mkLicense lset) ({ url = "https://fedoraproject.org/wiki/Licensing/GPL_Classpath_Exception"; }; + giftware = { + spdxId = "Giftware"; + fullName = "Giftware License"; + }; + hpnd = { spdxId = "HPND"; fullName = "Historic Permission Notice and Disclaimer"; @@ -609,6 +614,11 @@ in mkLicense lset) ({ spdxId = "HPND-sell-variant"; }; + hpndUc = { + spdxId = "HPND-UC"; + fullName = "Historical Permission Notice and Disclaimer - University of California variant"; + }; + # Intel's license, seems free iasl = { spdxId = "Intel-ACPI"; @@ -894,6 +904,11 @@ in mkLicense lset) ({ url = "https://raw.githubusercontent.com/netdata/netdata/master/web/gui/v2/LICENSE.md"; }; + nistSoftware = { + spdxId = "NIST-Software"; + fullName = "NIST Software License"; + }; + nlpl = { spdxId = "NLPL"; fullName = "No Limit Public License"; @@ -1251,11 +1266,6 @@ in mkLicense lset) ({ }; } // { # TODO: remove legacy aliases - agpl3 = { - spdxId = "AGPL-3.0"; - fullName = "GNU Affero General Public License v3.0"; - deprecated = true; - }; gpl2 = { spdxId = "GPL-2.0"; fullName = "GNU General Public License v2.0"; diff --git a/nixpkgs/lib/lists.nix b/nixpkgs/lib/lists.nix index 05216c1a66eb..c162f921280d 100644 --- a/nixpkgs/lib/lists.nix +++ b/nixpkgs/lib/lists.nix @@ -1,4 +1,6 @@ -/* General list operations. */ +/** + General list operations. +*/ { lib }: let inherit (lib.strings) toInt; @@ -9,45 +11,112 @@ rec { inherit (builtins) head tail length isList elemAt concatLists filter elem genList map; - /* Create a list consisting of a single element. `singleton x` is - sometimes more convenient with respect to indentation than `[x]` - when x spans multiple lines. + /** + Create a list consisting of a single element. `singleton x` is + sometimes more convenient with respect to indentation than `[x]` + when x spans multiple lines. - Type: singleton :: a -> [a] + # Inputs - Example: - singleton "foo" - => [ "foo" ] + `x` + + : 1\. Function argument + + # Type + + ``` + singleton :: a -> [a] + ``` + + # Examples + :::{.example} + ## `lib.lists.singleton` usage example + + ```nix + singleton "foo" + => [ "foo" ] + ``` + + ::: */ singleton = x: [x]; - /* Apply the function to each element in the list. Same as `map`, but arguments - flipped. + /** + Apply the function to each element in the list. + Same as `map`, but arguments flipped. + + # Inputs + + `xs` + + : 1\. Function argument + + `f` + + : 2\. Function argument + + # Type + + ``` + forEach :: [a] -> (a -> b) -> [b] + ``` + + # Examples + :::{.example} + ## `lib.lists.forEach` usage example - Type: forEach :: [a] -> (a -> b) -> [b] + ```nix + forEach [ 1 2 ] (x: + toString x + ) + => [ "1" "2" ] + ``` - Example: - forEach [ 1 2 ] (x: - toString x - ) - => [ "1" "2" ] + ::: */ forEach = xs: f: map f xs; - /* “right fold” a binary function `op` between successive elements of - `list` with `nul` as the starting value, i.e., - `foldr op nul [x_1 x_2 ... x_n] == op x_1 (op x_2 ... (op x_n nul))`. + /** + “right fold” a binary function `op` between successive elements of + `list` with `nul` as the starting value, i.e., + `foldr op nul [x_1 x_2 ... x_n] == op x_1 (op x_2 ... (op x_n nul))`. + + + # Inputs + + `op` + + : 1\. Function argument + + `nul` - Type: foldr :: (a -> b -> b) -> b -> [a] -> b + : 2\. Function argument - Example: - concat = foldr (a: b: a + b) "z" - concat [ "a" "b" "c" ] - => "abcz" - # different types - strange = foldr (int: str: toString (int + 1) + str) "a" - strange [ 1 2 3 4 ] - => "2345a" + `list` + + : 3\. Function argument + + # Type + + ``` + foldr :: (a -> b -> b) -> b -> [a] -> b + ``` + + # Examples + :::{.example} + ## `lib.lists.foldr` usage example + + ```nix + concat = foldr (a: b: a + b) "z" + concat [ "a" "b" "c" ] + => "abcz" + # different types + strange = foldr (int: str: toString (int + 1) + str) "a" + strange [ 1 2 3 4 ] + => "2345a" + ``` + + ::: */ foldr = op: nul: list: let @@ -58,24 +127,53 @@ rec { else op (elemAt list n) (fold' (n + 1)); in fold' 0; - /* `fold` is an alias of `foldr` for historic reasons */ + /** + `fold` is an alias of `foldr` for historic reasons + */ # FIXME(Profpatsch): deprecate? fold = foldr; - /* “left fold”, like `foldr`, but from the left: - `foldl op nul [x_1 x_2 ... x_n] == op (... (op (op nul x_1) x_2) ... x_n)`. + /** + “left fold”, like `foldr`, but from the left: + + `foldl op nul [x_1 x_2 ... x_n] == op (... (op (op nul x_1) x_2) ... x_n)`. + + # Inputs + + `op` + + : 1\. Function argument + + `nul` + + : 2\. Function argument + + `list` - Type: foldl :: (b -> a -> b) -> b -> [a] -> b + : 3\. Function argument - Example: - lconcat = foldl (a: b: a + b) "z" - lconcat [ "a" "b" "c" ] - => "zabc" - # different types - lstrange = foldl (str: int: str + toString (int + 1)) "a" - lstrange [ 1 2 3 4 ] - => "a2345" + # Type + + ``` + foldl :: (b -> a -> b) -> b -> [a] -> b + ``` + + # Examples + :::{.example} + ## `lib.lists.foldl` usage example + + ```nix + lconcat = foldl (a: b: a + b) "z" + lconcat [ "a" "b" "c" ] + => "zabc" + # different types + lstrange = foldl (str: int: str + toString (int + 1)) "a" + lstrange [ 1 2 3 4 ] + => "a2345" + ``` + + ::: */ foldl = op: nul: list: let @@ -85,7 +183,7 @@ rec { else op (foldl' (n - 1)) (elemAt list n); in foldl' (length list - 1); - /* + /** Reduce a list by applying a binary operator from left to right, starting with an initial accumulator. @@ -119,131 +217,305 @@ rec { op (op (... (op (op (op acc₀ x₀) x₁) x₂) ...) xₙ₋₁) xₙ ``` - Type: foldl' :: (acc -> x -> acc) -> acc -> [x] -> acc + # Inputs - Example: - foldl' (acc: x: acc + x) 0 [1 2 3] - => 6 - */ - foldl' = - /* The binary operation to run, where the two arguments are: + `op` + + : The binary operation to run, where the two arguments are: 1. `acc`: The current accumulator value: Either the initial one for the first iteration, or the result of the previous iteration 2. `x`: The corresponding list element for this iteration - */ + + `acc` + + : The initial accumulator value. + + The accumulator value is evaluated in any case before the first iteration starts. + + To avoid evaluation even before the `list` argument is given an eta expansion can be used: + + ```nix + list: lib.foldl' op acc list + ``` + + `list` + + : The list to fold + + # Type + + ``` + foldl' :: (acc -> x -> acc) -> acc -> [x] -> acc + ``` + + # Examples + :::{.example} + ## `lib.lists.foldl'` usage example + + ```nix + foldl' (acc: x: acc + x) 0 [1 2 3] + => 6 + ``` + + ::: + */ + foldl' = op: - # The initial accumulator value acc: - # The list to fold - list: - # The builtin `foldl'` is a bit lazier than one might expect. # See https://github.com/NixOS/nix/pull/7158. # In particular, the initial accumulator value is not forced before the first iteration starts. builtins.seq acc - (builtins.foldl' op acc list); + (builtins.foldl' op acc); + + /** + Map with index starting from 0 + + # Inputs + + `f` + + : 1\. Function argument - /* Map with index starting from 0 + `list` - Type: imap0 :: (int -> a -> b) -> [a] -> [b] + : 2\. Function argument - Example: - imap0 (i: v: "${v}-${toString i}") ["a" "b"] - => [ "a-0" "b-1" ] + # Type + + ``` + imap0 :: (int -> a -> b) -> [a] -> [b] + ``` + + # Examples + :::{.example} + ## `lib.lists.imap0` usage example + + ```nix + imap0 (i: v: "${v}-${toString i}") ["a" "b"] + => [ "a-0" "b-1" ] + ``` + + ::: */ imap0 = f: list: genList (n: f n (elemAt list n)) (length list); - /* Map with index starting from 1 + /** + Map with index starting from 1 + - Type: imap1 :: (int -> a -> b) -> [a] -> [b] + # Inputs - Example: - imap1 (i: v: "${v}-${toString i}") ["a" "b"] - => [ "a-1" "b-2" ] + `f` + + : 1\. Function argument + + `list` + + : 2\. Function argument + + # Type + + ``` + imap1 :: (int -> a -> b) -> [a] -> [b] + ``` + + # Examples + :::{.example} + ## `lib.lists.imap1` usage example + + ```nix + imap1 (i: v: "${v}-${toString i}") ["a" "b"] + => [ "a-1" "b-2" ] + ``` + + ::: */ imap1 = f: list: genList (n: f (n + 1) (elemAt list n)) (length list); - /* Map and concatenate the result. + /** + Map and concatenate the result. + + # Type + + ``` + concatMap :: (a -> [b]) -> [a] -> [b] + ``` + + # Examples + :::{.example} + ## `lib.lists.concatMap` usage example - Type: concatMap :: (a -> [b]) -> [a] -> [b] + ```nix + concatMap (x: [x] ++ ["z"]) ["a" "b"] + => [ "a" "z" "b" "z" ] + ``` - Example: - concatMap (x: [x] ++ ["z"]) ["a" "b"] - => [ "a" "z" "b" "z" ] + ::: */ concatMap = builtins.concatMap; - /* Flatten the argument into a single list; that is, nested lists are - spliced into the top-level lists. + /** + Flatten the argument into a single list; that is, nested lists are + spliced into the top-level lists. + + + # Inputs + + `x` + + : 1\. Function argument + + + # Examples + :::{.example} + ## `lib.lists.flatten` usage example + + ```nix + flatten [1 [2 [3] 4] 5] + => [1 2 3 4 5] + flatten 1 + => [1] + ``` - Example: - flatten [1 [2 [3] 4] 5] - => [1 2 3 4 5] - flatten 1 - => [1] + ::: */ flatten = x: if isList x then concatMap (y: flatten y) x else [x]; - /* Remove elements equal to 'e' from a list. Useful for buildInputs. + /** + Remove elements equal to 'e' from a list. Useful for buildInputs. + + + # Inputs + + `e` - Type: remove :: a -> [a] -> [a] + : Element to remove from `list` - Example: - remove 3 [ 1 3 4 3 ] - => [ 1 4 ] + `list` + + : The list + + # Type + + ``` + remove :: a -> [a] -> [a] + ``` + + # Examples + :::{.example} + ## `lib.lists.remove` usage example + + ```nix + remove 3 [ 1 3 4 3 ] + => [ 1 4 ] + ``` + + ::: */ remove = - # Element to remove from the list e: filter (x: x != e); - /* Find the sole element in the list matching the specified - predicate, returns `default` if no such element exists, or - `multiple` if there are multiple matching elements. + /** + Find the sole element in the list matching the specified + predicate. + + Returns `default` if no such element exists, or + `multiple` if there are multiple matching elements. + + + # Inputs + + `pred` + + : Predicate + + `default` + + : Default value to return if element was not found. + + `multiple` + + : Default value to return if more than one element was found + + `list` + + : Input list - Type: findSingle :: (a -> bool) -> a -> a -> [a] -> a + # Type - Example: - findSingle (x: x == 3) "none" "multiple" [ 1 3 3 ] - => "multiple" - findSingle (x: x == 3) "none" "multiple" [ 1 3 ] - => 3 - findSingle (x: x == 3) "none" "multiple" [ 1 9 ] - => "none" + ``` + findSingle :: (a -> bool) -> a -> a -> [a] -> a + ``` + + # Examples + :::{.example} + ## `lib.lists.findSingle` usage example + + ```nix + findSingle (x: x == 3) "none" "multiple" [ 1 3 3 ] + => "multiple" + findSingle (x: x == 3) "none" "multiple" [ 1 3 ] + => 3 + findSingle (x: x == 3) "none" "multiple" [ 1 9 ] + => "none" + ``` + + ::: */ findSingle = - # Predicate pred: - # Default value to return if element was not found. default: - # Default value to return if more than one element was found multiple: - # Input list list: let found = filter pred list; len = length found; in if len == 0 then default else if len != 1 then multiple else head found; - /* Find the first index in the list matching the specified - predicate or return `default` if no such element exists. + /** + Find the first index in the list matching the specified + predicate or return `default` if no such element exists. + + # Inputs + + `pred` + + : Predicate + + `default` + + : Default value to return + + `list` + + : Input list + + # Type + + ``` + findFirstIndex :: (a -> Bool) -> b -> [a] -> (Int | b) + ``` - Type: findFirstIndex :: (a -> Bool) -> b -> [a] -> (Int | b) + # Examples + :::{.example} + ## `lib.lists.findFirstIndex` usage example - Example: - findFirstIndex (x: x > 3) null [ 0 6 4 ] - => 1 - findFirstIndex (x: x > 9) null [ 0 6 4 ] - => null + ```nix + findFirstIndex (x: x > 3) null [ 0 6 4 ] + => 1 + findFirstIndex (x: x > 9) null [ 0 6 4 ] + => null + ``` + + ::: */ findFirstIndex = - # Predicate pred: - # Default value to return default: - # Input list list: let # A naive recursive implementation would be much simpler, but @@ -278,23 +550,46 @@ rec { else resultIndex; - /* Find the first element in the list matching the specified - predicate or return `default` if no such element exists. + /** + Find the first element in the list matching the specified + predicate or return `default` if no such element exists. + + # Inputs + + `pred` + + : Predicate + + `default` + + : Default value to return + + `list` - Type: findFirst :: (a -> bool) -> a -> [a] -> a + : Input list + + # Type + + ``` + findFirst :: (a -> bool) -> a -> [a] -> a + ``` + + # Examples + :::{.example} + ## `lib.lists.findFirst` usage example + + ```nix + findFirst (x: x > 3) 7 [ 1 6 4 ] + => 6 + findFirst (x: x > 9) 7 [ 1 6 4 ] + => 7 + ``` - Example: - findFirst (x: x > 3) 7 [ 1 6 4 ] - => 6 - findFirst (x: x > 9) 7 [ 1 6 4 ] - => 7 + ::: */ findFirst = - # Predicate pred: - # Default value to return default: - # Input list list: let index = findFirstIndex pred null list; @@ -304,152 +599,359 @@ rec { else elemAt list index; - /* Return true if function `pred` returns true for at least one - element of `list`. + /** + Return true if function `pred` returns true for at least one + element of `list`. - Type: any :: (a -> bool) -> [a] -> bool + # Inputs - Example: - any isString [ 1 "a" { } ] - => true - any isString [ 1 { } ] - => false + `pred` + + : Predicate + + `list` + + : Input list + + # Type + + ``` + any :: (a -> bool) -> [a] -> bool + ``` + + # Examples + :::{.example} + ## `lib.lists.any` usage example + + ```nix + any isString [ 1 "a" { } ] + => true + any isString [ 1 { } ] + => false + ``` + + ::: */ any = builtins.any; - /* Return true if function `pred` returns true for all elements of - `list`. + /** + Return true if function `pred` returns true for all elements of + `list`. + + # Inputs + + `pred` + + : Predicate + + `list` - Type: all :: (a -> bool) -> [a] -> bool + : Input list - Example: - all (x: x < 3) [ 1 2 ] - => true - all (x: x < 3) [ 1 2 3 ] - => false + # Type + + ``` + all :: (a -> bool) -> [a] -> bool + ``` + + # Examples + :::{.example} + ## `lib.lists.all` usage example + + ```nix + all (x: x < 3) [ 1 2 ] + => true + all (x: x < 3) [ 1 2 3 ] + => false + ``` + + ::: */ all = builtins.all; - /* Count how many elements of `list` match the supplied predicate - function. + /** + Count how many elements of `list` match the supplied predicate + function. + + # Inputs + + `pred` + + : Predicate + + # Type + + ``` + count :: (a -> bool) -> [a] -> int + ``` + + # Examples + :::{.example} + ## `lib.lists.count` usage example - Type: count :: (a -> bool) -> [a] -> int + ```nix + count (x: x == 3) [ 3 2 3 4 6 ] + => 2 + ``` - Example: - count (x: x == 3) [ 3 2 3 4 6 ] - => 2 + ::: */ count = - # Predicate pred: foldl' (c: x: if pred x then c + 1 else c) 0; - /* Return a singleton list or an empty list, depending on a boolean - value. Useful when building lists with optional elements - (e.g. `++ optional (system == "i686-linux") firefox`). + /** + Return a singleton list or an empty list, depending on a boolean + value. Useful when building lists with optional elements + (e.g. `++ optional (system == "i686-linux") firefox`). + + # Inputs + + `cond` + + : 1\. Function argument + + `elem` + + : 2\. Function argument + + # Type - Type: optional :: bool -> a -> [a] + ``` + optional :: bool -> a -> [a] + ``` + + # Examples + :::{.example} + ## `lib.lists.optional` usage example - Example: - optional true "foo" - => [ "foo" ] - optional false "foo" - => [ ] + ```nix + optional true "foo" + => [ "foo" ] + optional false "foo" + => [ ] + ``` + + ::: */ optional = cond: elem: if cond then [elem] else []; - /* Return a list or an empty list, depending on a boolean value. + /** + Return a list or an empty list, depending on a boolean value. + + # Inputs + + `cond` - Type: optionals :: bool -> [a] -> [a] + : Condition - Example: - optionals true [ 2 3 ] - => [ 2 3 ] - optionals false [ 2 3 ] - => [ ] + `elems` + + : List to return if condition is true + + # Type + + ``` + optionals :: bool -> [a] -> [a] + ``` + + # Examples + :::{.example} + ## `lib.lists.optionals` usage example + + ```nix + optionals true [ 2 3 ] + => [ 2 3 ] + optionals false [ 2 3 ] + => [ ] + ``` + + ::: */ optionals = - # Condition cond: - # List to return if condition is true elems: if cond then elems else []; - /* If argument is a list, return it; else, wrap it in a singleton - list. If you're using this, you should almost certainly - reconsider if there isn't a more "well-typed" approach. + /** + If argument is a list, return it; else, wrap it in a singleton + list. If you're using this, you should almost certainly + reconsider if there isn't a more "well-typed" approach. + + # Inputs + + `x` + + : 1\. Function argument + + # Examples + :::{.example} + ## `lib.lists.toList` usage example + + ```nix + toList [ 1 2 ] + => [ 1 2 ] + toList "hi" + => [ "hi "] + ``` - Example: - toList [ 1 2 ] - => [ 1 2 ] - toList "hi" - => [ "hi "] + ::: */ toList = x: if isList x then x else [x]; - /* Return a list of integers from `first` up to and including `last`. + /** + Return a list of integers from `first` up to and including `last`. + + # Inputs + + `first` + + : First integer in the range + + `last` + + : Last integer in the range + + # Type + + ``` + range :: int -> int -> [int] + ``` - Type: range :: int -> int -> [int] + # Examples + :::{.example} + ## `lib.lists.range` usage example - Example: - range 2 4 - => [ 2 3 4 ] - range 3 2 - => [ ] + ```nix + range 2 4 + => [ 2 3 4 ] + range 3 2 + => [ ] + ``` + + ::: */ range = - # First integer in the range first: - # Last integer in the range last: if first > last then [] else genList (n: first + n) (last - first + 1); - /* Return a list with `n` copies of an element. + /** + Return a list with `n` copies of an element. + + # Inputs + + `n` + + : 1\. Function argument - Type: replicate :: int -> a -> [a] + `elem` - Example: - replicate 3 "a" - => [ "a" "a" "a" ] - replicate 2 true - => [ true true ] + : 2\. Function argument + + # Type + + ``` + replicate :: int -> a -> [a] + ``` + + # Examples + :::{.example} + ## `lib.lists.replicate` usage example + + ```nix + replicate 3 "a" + => [ "a" "a" "a" ] + replicate 2 true + => [ true true ] + ``` + + ::: */ replicate = n: elem: genList (_: elem) n; - /* Splits the elements of a list in two lists, `right` and - `wrong`, depending on the evaluation of a predicate. + /** + Splits the elements of a list in two lists, `right` and + `wrong`, depending on the evaluation of a predicate. + + # Inputs + + `pred` + + : Predicate + + `list` + + : Input list + + # Type + + ``` + (a -> bool) -> [a] -> { right :: [a]; wrong :: [a]; } + ``` + + # Examples + :::{.example} + ## `lib.lists.partition` usage example - Type: (a -> bool) -> [a] -> { right :: [a]; wrong :: [a]; } + ```nix + partition (x: x > 2) [ 5 1 2 3 4 ] + => { right = [ 5 3 4 ]; wrong = [ 1 2 ]; } + ``` - Example: - partition (x: x > 2) [ 5 1 2 3 4 ] - => { right = [ 5 3 4 ]; wrong = [ 1 2 ]; } + ::: */ partition = builtins.partition; - /* Splits the elements of a list into many lists, using the return value of a predicate. - Predicate should return a string which becomes keys of attrset `groupBy` returns. + /** + Splits the elements of a list into many lists, using the return value of a predicate. + Predicate should return a string which becomes keys of attrset `groupBy` returns. + `groupBy'` allows to customise the combining function and initial value + + # Inputs + + `op` + + : 1\. Function argument + + `nul` + + : 2\. Function argument - `groupBy'` allows to customise the combining function and initial value + `pred` - Example: - groupBy (x: boolToString (x > 2)) [ 5 1 2 3 4 ] - => { true = [ 5 3 4 ]; false = [ 1 2 ]; } - groupBy (x: x.name) [ {name = "icewm"; script = "icewm &";} - {name = "xfce"; script = "xfce4-session &";} - {name = "icewm"; script = "icewmbg &";} - {name = "mate"; script = "gnome-session &";} - ] - => { icewm = [ { name = "icewm"; script = "icewm &"; } - { name = "icewm"; script = "icewmbg &"; } ]; - mate = [ { name = "mate"; script = "gnome-session &"; } ]; - xfce = [ { name = "xfce"; script = "xfce4-session &"; } ]; - } + : 3\. Function argument - groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ] - => { true = 12; false = 3; } + `lst` + + : 4\. Function argument + + + # Examples + :::{.example} + ## `lib.lists.groupBy'` usage example + + ```nix + groupBy (x: boolToString (x > 2)) [ 5 1 2 3 4 ] + => { true = [ 5 3 4 ]; false = [ 1 2 ]; } + groupBy (x: x.name) [ {name = "icewm"; script = "icewm &";} + {name = "xfce"; script = "xfce4-session &";} + {name = "icewm"; script = "icewmbg &";} + {name = "mate"; script = "gnome-session &";} + ] + => { icewm = [ { name = "icewm"; script = "icewm &"; } + { name = "icewm"; script = "icewmbg &"; } ]; + mate = [ { name = "mate"; script = "gnome-session &"; } ]; + xfce = [ { name = "xfce"; script = "xfce4-session &"; } ]; + } + + groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ] + => { true = 12; false = 3; } + ``` + + ::: */ groupBy' = op: nul: pred: lst: mapAttrs (name: foldl op nul) (groupBy pred lst); @@ -461,68 +963,153 @@ rec { r // { ${key} = (r.${key} or []) ++ [e]; } ) {}); - /* Merges two lists of the same size together. If the sizes aren't the same - the merging stops at the shortest. How both lists are merged is defined - by the first argument. + /** + Merges two lists of the same size together. If the sizes aren't the same + the merging stops at the shortest. How both lists are merged is defined + by the first argument. + + # Inputs + + `f` - Type: zipListsWith :: (a -> b -> c) -> [a] -> [b] -> [c] + : Function to zip elements of both lists - Example: - zipListsWith (a: b: a + b) ["h" "l"] ["e" "o"] - => ["he" "lo"] + `fst` + + : First list + + `snd` + + : Second list + + # Type + + ``` + zipListsWith :: (a -> b -> c) -> [a] -> [b] -> [c] + ``` + + # Examples + :::{.example} + ## `lib.lists.zipListsWith` usage example + + ```nix + zipListsWith (a: b: a + b) ["h" "l"] ["e" "o"] + => ["he" "lo"] + ``` + + ::: */ zipListsWith = - # Function to zip elements of both lists f: - # First list fst: - # Second list snd: genList (n: f (elemAt fst n) (elemAt snd n)) (min (length fst) (length snd)); - /* Merges two lists of the same size together. If the sizes aren't the same - the merging stops at the shortest. + /** + Merges two lists of the same size together. If the sizes aren't the same + the merging stops at the shortest. + + # Inputs + + `fst` - Type: zipLists :: [a] -> [b] -> [{ fst :: a; snd :: b; }] + : First list - Example: - zipLists [ 1 2 ] [ "a" "b" ] - => [ { fst = 1; snd = "a"; } { fst = 2; snd = "b"; } ] + `snd` + + : Second list + + # Type + + ``` + zipLists :: [a] -> [b] -> [{ fst :: a; snd :: b; }] + ``` + + # Examples + :::{.example} + ## `lib.lists.zipLists` usage example + + ```nix + zipLists [ 1 2 ] [ "a" "b" ] + => [ { fst = 1; snd = "a"; } { fst = 2; snd = "b"; } ] + ``` + + ::: */ zipLists = zipListsWith (fst: snd: { inherit fst snd; }); - /* Reverse the order of the elements of a list. + /** + Reverse the order of the elements of a list. + + # Inputs + + `xs` + + : 1\. Function argument - Type: reverseList :: [a] -> [a] + # Type - Example: + ``` + reverseList :: [a] -> [a] + ``` + + # Examples + :::{.example} + ## `lib.lists.reverseList` usage example - reverseList [ "b" "o" "j" ] - => [ "j" "o" "b" ] + ```nix + reverseList [ "b" "o" "j" ] + => [ "j" "o" "b" ] + ``` + + ::: */ reverseList = xs: let l = length xs; in genList (n: elemAt xs (l - n - 1)) l; - /* Depth-First Search (DFS) for lists `list != []`. + /** + Depth-First Search (DFS) for lists `list != []`. + + `before a b == true` means that `b` depends on `a` (there's an + edge from `b` to `a`). + + + # Inputs - `before a b == true` means that `b` depends on `a` (there's an - edge from `b` to `a`). + `stopOnCycles` - Example: - listDfs true hasPrefix [ "/home/user" "other" "/" "/home" ] - == { minimal = "/"; # minimal element - visited = [ "/home/user" ]; # seen elements (in reverse order) - rest = [ "/home" "other" ]; # everything else - } + : 1\. Function argument - listDfs true hasPrefix [ "/home/user" "other" "/" "/home" "/" ] - == { cycle = "/"; # cycle encountered at this element - loops = [ "/" ]; # and continues to these elements - visited = [ "/" "/home/user" ]; # elements leading to the cycle (in reverse order) - rest = [ "/home" "other" ]; # everything else + `before` - */ + : 2\. Function argument + + `list` + + : 3\. Function argument + + + # Examples + :::{.example} + ## `lib.lists.listDfs` usage example + + ```nix + listDfs true hasPrefix [ "/home/user" "other" "/" "/home" ] + == { minimal = "/"; # minimal element + visited = [ "/home/user" ]; # seen elements (in reverse order) + rest = [ "/home" "other" ]; # everything else + } + + listDfs true hasPrefix [ "/home/user" "other" "/" "/home" "/" ] + == { cycle = "/"; # cycle encountered at this element + loops = [ "/" ]; # and continues to these elements + visited = [ "/" "/home/user" ]; # elements leading to the cycle (in reverse order) + rest = [ "/home" "other" ]; # everything else + ``` + + ::: + */ listDfs = stopOnCycles: before: list: let dfs' = us: visited: rest: @@ -540,28 +1127,46 @@ rec { (tail b.right ++ b.wrong); in dfs' (head list) [] (tail list); - /* Sort a list based on a partial ordering using DFS. This - implementation is O(N^2), if your ordering is linear, use `sort` - instead. + /** + Sort a list based on a partial ordering using DFS. This + implementation is O(N^2), if your ordering is linear, use `sort` + instead. - `before a b == true` means that `b` should be after `a` - in the result. + `before a b == true` means that `b` should be after `a` + in the result. - Example: - toposort hasPrefix [ "/home/user" "other" "/" "/home" ] - == { result = [ "/" "/home" "/home/user" "other" ]; } + # Inputs - toposort hasPrefix [ "/home/user" "other" "/" "/home" "/" ] - == { cycle = [ "/home/user" "/" "/" ]; # path leading to a cycle - loops = [ "/" ]; } # loops back to these elements + `before` - toposort hasPrefix [ "other" "/home/user" "/home" "/" ] - == { result = [ "other" "/" "/home" "/home/user" ]; } + : 1\. Function argument - toposort (a: b: a < b) [ 3 2 1 ] == { result = [ 1 2 3 ]; } + `list` - */ + : 2\. Function argument + + + # Examples + :::{.example} + ## `lib.lists.toposort` usage example + + ```nix + toposort hasPrefix [ "/home/user" "other" "/" "/home" ] + == { result = [ "/" "/home" "/home/user" "other" ]; } + + toposort hasPrefix [ "/home/user" "other" "/" "/home" "/" ] + == { cycle = [ "/home/user" "/" "/" ]; # path leading to a cycle + loops = [ "/" ]; } # loops back to these elements + + toposort hasPrefix [ "other" "/home/user" "/home" "/" ] + == { result = [ "other" "/" "/home" "/home/user" ]; } + + toposort (a: b: a < b) [ 3 2 1 ] == { result = [ 1 2 3 ]; } + ``` + + ::: + */ toposort = before: list: let dfsthis = listDfs true before list; @@ -581,24 +1186,45 @@ rec { else # there are no cycles { result = [ dfsthis.minimal ] ++ toporest.result; }; - /* Sort a list based on a comparator function which compares two - elements and returns true if the first argument is strictly below - the second argument. The returned list is sorted in an increasing - order. The implementation does a quick-sort. + /** + Sort a list based on a comparator function which compares two + elements and returns true if the first argument is strictly below + the second argument. The returned list is sorted in an increasing + order. The implementation does a quick-sort. + + See also [`sortOn`](#function-library-lib.lists.sortOn), which applies the + default comparison on a function-derived property, and may be more efficient. + + # Inputs + + `comparator` + + : 1\. Function argument + + `list` + + : 2\. Function argument + + # Type - See also [`sortOn`](#function-library-lib.lists.sortOn), which applies the - default comparison on a function-derived property, and may be more efficient. + ``` + sort :: (a -> a -> Bool) -> [a] -> [a] + ``` + + # Examples + :::{.example} + ## `lib.lists.sort` usage example - Example: - sort (p: q: p < q) [ 5 3 7 ] - => [ 3 5 7 ] + ```nix + sort (p: q: p < q) [ 5 3 7 ] + => [ 3 5 7 ] + ``` - Type: - sort :: (a -> a -> Bool) -> [a] -> [a] + ::: */ sort = builtins.sort; - /* + /** Sort a list based on the default comparison of a derived property `b`. The items are returned in `b`-increasing order. @@ -614,12 +1240,33 @@ rec { sortOn f == sort (p: q: f p < f q) ``` - Example: - sortOn stringLength [ "aa" "b" "cccc" ] - => [ "b" "aa" "cccc" ] - Type: - sortOn :: (a -> b) -> [a] -> [a], for comparable b + # Inputs + + `f` + + : 1\. Function argument + + `list` + + : 2\. Function argument + + # Type + + ``` + sortOn :: (a -> b) -> [a] -> [a], for comparable b + ``` + + # Examples + :::{.example} + ## `lib.lists.sortOn` usage example + + ```nix + sortOn stringLength [ "aa" "b" "cccc" ] + => [ "b" "aa" "cccc" ] + ``` + + ::: */ sortOn = f: list: let @@ -634,17 +1281,40 @@ rec { (a: b: head a < head b) pairs); - /* Compare two lists element-by-element. + /** + Compare two lists element-by-element. + + # Inputs + + `cmp` + + : 1\. Function argument + + `a` + + : 2\. Function argument + + `b` + + : 3\. Function argument + - Example: - compareLists compare [] [] - => 0 - compareLists compare [] [ "a" ] - => -1 - compareLists compare [ "a" ] [] - => 1 - compareLists compare [ "a" "b" ] [ "a" "c" ] - => -1 + # Examples + :::{.example} + ## `lib.lists.compareLists` usage example + + ```nix + compareLists compare [] [] + => 0 + compareLists compare [] [ "a" ] + => -1 + compareLists compare [ "a" ] [] + => 1 + compareLists compare [ "a" "b" ] [ "a" "c" ] + => -1 + ``` + + ::: */ compareLists = cmp: a: b: if a == [] @@ -658,16 +1328,32 @@ rec { then compareLists cmp (tail a) (tail b) else rel; - /* Sort list using "Natural sorting". - Numeric portions of strings are sorted in numeric order. + /** + Sort list using "Natural sorting". + Numeric portions of strings are sorted in numeric order. + + + # Inputs + + `lst` + + : 1\. Function argument + - Example: - naturalSort ["disk11" "disk8" "disk100" "disk9"] - => ["disk8" "disk9" "disk11" "disk100"] - naturalSort ["10.46.133.149" "10.5.16.62" "10.54.16.25"] - => ["10.5.16.62" "10.46.133.149" "10.54.16.25"] - naturalSort ["v0.2" "v0.15" "v0.0.9"] - => [ "v0.0.9" "v0.2" "v0.15" ] + # Examples + :::{.example} + ## `lib.lists.naturalSort` usage example + + ```nix + naturalSort ["disk11" "disk8" "disk100" "disk9"] + => ["disk8" "disk9" "disk11" "disk100"] + naturalSort ["10.46.133.149" "10.5.16.62" "10.54.16.25"] + => ["10.5.16.62" "10.46.133.149" "10.54.16.25"] + naturalSort ["v0.2" "v0.15" "v0.0.9"] + => [ "v0.0.9" "v0.2" "v0.15" ] + ``` + + ::: */ naturalSort = lst: let @@ -677,61 +1363,149 @@ rec { in map (x: elemAt x 1) (sort less prepared); - /* Return the first (at most) N elements of a list. + /** + Return the first (at most) N elements of a list. + + + # Inputs + + `count` + + : Number of elements to take + + `list` - Type: take :: int -> [a] -> [a] + : Input list - Example: - take 2 [ "a" "b" "c" "d" ] - => [ "a" "b" ] - take 2 [ ] - => [ ] + # Type + + ``` + take :: int -> [a] -> [a] + ``` + + # Examples + :::{.example} + ## `lib.lists.take` usage example + + ```nix + take 2 [ "a" "b" "c" "d" ] + => [ "a" "b" ] + take 2 [ ] + => [ ] + ``` + + ::: */ take = - # Number of elements to take count: sublist 0 count; - /* Remove the first (at most) N elements of a list. + /** + Remove the first (at most) N elements of a list. - Type: drop :: int -> [a] -> [a] - Example: - drop 2 [ "a" "b" "c" "d" ] - => [ "c" "d" ] - drop 2 [ ] - => [ ] + # Inputs + + `count` + + : Number of elements to drop + + `list` + + : Input list + + # Type + + ``` + drop :: int -> [a] -> [a] + ``` + + # Examples + :::{.example} + ## `lib.lists.drop` usage example + + ```nix + drop 2 [ "a" "b" "c" "d" ] + => [ "c" "d" ] + drop 2 [ ] + => [ ] + ``` + + ::: */ drop = - # Number of elements to drop count: - # Input list list: sublist count (length list) list; - /* Whether the first list is a prefix of the second list. + /** + Whether the first list is a prefix of the second list. + + + # Inputs + + `list1` - Type: hasPrefix :: [a] -> [a] -> bool + : 1\. Function argument - Example: + `list2` + + : 2\. Function argument + + # Type + + ``` + hasPrefix :: [a] -> [a] -> bool + ``` + + # Examples + :::{.example} + ## `lib.lists.hasPrefix` usage example + + ```nix hasPrefix [ 1 2 ] [ 1 2 3 4 ] => true hasPrefix [ 0 1 ] [ 1 2 3 4 ] => false + ``` + + ::: */ hasPrefix = list1: list2: take (length list1) list2 == list1; - /* Remove the first list as a prefix from the second list. - Error if the first list isn't a prefix of the second list. + /** + Remove the first list as a prefix from the second list. + Error if the first list isn't a prefix of the second list. + + # Inputs + + `list1` + + : 1\. Function argument + + `list2` - Type: removePrefix :: [a] -> [a] -> [a] + : 2\. Function argument + + # Type + + ``` + removePrefix :: [a] -> [a] -> [a] + ``` - Example: + # Examples + :::{.example} + ## `lib.lists.removePrefix` usage example + + ```nix removePrefix [ 1 2 ] [ 1 2 3 4 ] => [ 3 4 ] removePrefix [ 0 1 ] [ 1 2 3 4 ] => <error> + ``` + + ::: */ removePrefix = list1: @@ -741,23 +1515,46 @@ rec { else throw "lib.lists.removePrefix: First argument is not a list prefix of the second argument"; - /* Return a list consisting of at most `count` elements of `list`, - starting at index `start`. + /** + Return a list consisting of at most `count` elements of `list`, + starting at index `start`. + + # Inputs + + `start` + + : Index at which to start the sublist + + `count` - Type: sublist :: int -> int -> [a] -> [a] + : Number of elements to take - Example: - sublist 1 3 [ "a" "b" "c" "d" "e" ] - => [ "b" "c" "d" ] - sublist 1 3 [ ] - => [ ] + `list` + + : Input list + + # Type + + ``` + sublist :: int -> int -> [a] -> [a] + ``` + + # Examples + :::{.example} + ## `lib.lists.sublist` usage example + + ```nix + sublist 1 3 [ "a" "b" "c" "d" "e" ] + => [ "b" "c" "d" ] + sublist 1 3 [ ] + => [ ] + ``` + + ::: */ sublist = - # Index at which to start the sublist start: - # Number of elements to take count: - # Input list list: let len = length list; in genList @@ -766,17 +1563,40 @@ rec { else if start + count > len then len - start else count); - /* The common prefix of two lists. + /** + The common prefix of two lists. + + + # Inputs + + `list1` - Type: commonPrefix :: [a] -> [a] -> [a] + : 1\. Function argument - Example: + `list2` + + : 2\. Function argument + + # Type + + ``` + commonPrefix :: [a] -> [a] -> [a] + ``` + + # Examples + :::{.example} + ## `lib.lists.commonPrefix` usage example + + ```nix commonPrefix [ 1 2 3 4 5 6 ] [ 1 2 4 8 ] => [ 1 2 ] commonPrefix [ 1 2 3 ] [ 1 2 3 4 5 ] => [ 1 2 3 ] commonPrefix [ 1 2 3 ] [ 4 5 6 ] => [ ] + ``` + + ::: */ commonPrefix = list1: @@ -792,87 +1612,225 @@ rec { in take commonPrefixLength list1; - /* Return the last element of a list. + /** + Return the last element of a list. + + This function throws an error if the list is empty. + + + # Inputs - This function throws an error if the list is empty. + `list` - Type: last :: [a] -> a + : 1\. Function argument + + # Type + + ``` + last :: [a] -> a + ``` + + # Examples + :::{.example} + ## `lib.lists.last` usage example + + ```nix + last [ 1 2 3 ] + => 3 + ``` - Example: - last [ 1 2 3 ] - => 3 + ::: */ last = list: assert lib.assertMsg (list != []) "lists.last: list must not be empty!"; elemAt list (length list - 1); - /* Return all elements but the last. + /** + Return all elements but the last. - This function throws an error if the list is empty. + This function throws an error if the list is empty. - Type: init :: [a] -> [a] - Example: - init [ 1 2 3 ] - => [ 1 2 ] + # Inputs + + `list` + + : 1\. Function argument + + # Type + + ``` + init :: [a] -> [a] + ``` + + # Examples + :::{.example} + ## `lib.lists.init` usage example + + ```nix + init [ 1 2 3 ] + => [ 1 2 ] + ``` + + ::: */ init = list: assert lib.assertMsg (list != []) "lists.init: list must not be empty!"; take (length list - 1) list; - /* Return the image of the cross product of some lists by a function. + /** + Return the image of the cross product of some lists by a function. + + + # Examples + :::{.example} + ## `lib.lists.crossLists` usage example - Example: - crossLists (x:y: "${toString x}${toString y}") [[1 2] [3 4]] - => [ "13" "14" "23" "24" ] + ```nix + crossLists (x:y: "${toString x}${toString y}") [[1 2] [3 4]] + => [ "13" "14" "23" "24" ] + ``` + + ::: */ crossLists = warn "lib.crossLists is deprecated, use lib.cartesianProductOfSets instead." (f: foldl (fs: args: concatMap (f: map f args) fs) [f]); - /* Remove duplicate elements from the list. O(n^2) complexity. + /** + Remove duplicate elements from the `list`. O(n^2) complexity. + - Type: unique :: [a] -> [a] + # Inputs - Example: - unique [ 3 2 3 4 ] - => [ 3 2 4 ] - */ + `list` + + : Input list + + # Type + + ``` + unique :: [a] -> [a] + ``` + + # Examples + :::{.example} + ## `lib.lists.unique` usage example + + ```nix + unique [ 3 2 3 4 ] + => [ 3 2 4 ] + ``` + + ::: + */ unique = foldl' (acc: e: if elem e acc then acc else acc ++ [ e ]) []; - /* Check if list contains only unique elements. O(n^2) complexity. + /** + Check if list contains only unique elements. O(n^2) complexity. + + + # Inputs + + `list` + + : 1\. Function argument + + # Type + + ``` + allUnique :: [a] -> bool + ``` - Type: allUnique :: [a] -> bool + # Examples + :::{.example} + ## `lib.lists.allUnique` usage example - Example: - allUnique [ 3 2 3 4 ] - => false - allUnique [ 3 2 4 1 ] - => true - */ + ```nix + allUnique [ 3 2 3 4 ] + => false + allUnique [ 3 2 4 1 ] + => true + ``` + + ::: + */ allUnique = list: (length (unique list) == length list); - /* Intersects list 'e' and another list. O(nm) complexity. + /** + Intersects list 'list1' and another list (`list2`). + + O(nm) complexity. - Example: - intersectLists [ 1 2 3 ] [ 6 3 2 ] - => [ 3 2 ] + # Inputs + + `list1` + + : First list + + `list2` + + : Second list + + + # Examples + :::{.example} + ## `lib.lists.intersectLists` usage example + + ```nix + intersectLists [ 1 2 3 ] [ 6 3 2 ] + => [ 3 2 ] + ``` + + ::: */ intersectLists = e: filter (x: elem x e); - /* Subtracts list 'e' from another list. O(nm) complexity. + /** + Subtracts list 'e' from another list (`list2`). + + O(nm) complexity. + + # Inputs + + `e` + + : First list + + `list2` + + : Second list + + + # Examples + :::{.example} + ## `lib.lists.subtractLists` usage example - Example: - subtractLists [ 3 2 ] [ 1 2 3 4 5 3 ] - => [ 1 4 5 ] + ```nix + subtractLists [ 3 2 ] [ 1 2 3 4 5 3 ] + => [ 1 4 5 ] + ``` + + ::: */ subtractLists = e: filter (x: !(elem x e)); - /* Test if two lists have no common element. - It should be slightly more efficient than (intersectLists a b == []) + /** + Test if two lists have no common element. + It should be slightly more efficient than (intersectLists a b == []) + + # Inputs + + `a` + + : 1\. Function argument + + `b` + + : 2\. Function argument */ mutuallyExclusive = a: b: length a == 0 || !(any (x: elem x a) b); diff --git a/nixpkgs/lib/systems/default.nix b/nixpkgs/lib/systems/default.nix index 6137d47e91a2..a71ea9209cb8 100644 --- a/nixpkgs/lib/systems/default.nix +++ b/nixpkgs/lib/systems/default.nix @@ -243,10 +243,14 @@ rec { vncSupport = false; gtkSupport = false; sdlSupport = false; + alsaSupport = false; pulseSupport = false; pipewireSupport = false; + jackSupport = false; smbdSupport = false; seccompSupport = false; + tpmSupport = false; + capstoneSupport = false; enableDocs = false; hostCpuTargets = [ "${final.qemuArch}-linux-user" ]; }; diff --git a/nixpkgs/lib/tests/misc.nix b/nixpkgs/lib/tests/misc.nix index 98d1f4e71c48..6f1d9039db80 100644 --- a/nixpkgs/lib/tests/misc.nix +++ b/nixpkgs/lib/tests/misc.nix @@ -13,9 +13,96 @@ Alternatively, to run all `lib` tests: [nixpkgs]$ nix-build lib/tests/release.nix */ -with import ../default.nix; let + lib = import ../default.nix; + + inherit (lib) + allUnique + and + attrNames + attrsets + attrsToList + bitAnd + bitOr + bitXor + boolToString + callPackagesWith + callPackageWith + cartesianProductOfSets + cli + composeExtensions + composeManyExtensions + concatLines + concatMapAttrs + concatMapStrings + concatStrings + concatStringsSep + const + escapeXML + evalModules + filter + fix + fold + foldAttrs + foldl + foldl' + foldlAttrs + foldr + functionArgs + generators + genList + getExe + getExe' + groupBy + groupBy' + hasAttrByPath + hasInfix + id + isStorePath + lazyDerivation + lists + listToAttrs + makeExtensible + makeOverridable + mapAttrs + matchAttrs + mergeAttrs + meta + mkOption + mod + nameValuePair + optionalDrvAttr + optionAttrSetToDocList + overrideExisting + packagesFromDirectoryRecursive + pipe + range + recursiveUpdateUntil + removePrefix + replicate + runTests + setFunctionArgs + showAttrPath + sort + sortOn + stringLength + strings + stringToCharacters + systems + tail + take + testAllTrue + toBaseDigits + toHexString + toInt + toIntBase10 + toShellVars + types + updateManyAttrsByPath + versions + ; + testingThrow = expr: { expr = (builtins.tryEval (builtins.seq expr "didn't throw")); expected = { success = false; value = false; }; diff --git a/nixpkgs/lib/tests/modules/alias-with-priority-can-override.nix b/nixpkgs/lib/tests/modules/alias-with-priority-can-override.nix index 9a18c9d9f613..82a4c0df8cba 100644 --- a/nixpkgs/lib/tests/modules/alias-with-priority-can-override.nix +++ b/nixpkgs/lib/tests/modules/alias-with-priority-can-override.nix @@ -6,12 +6,19 @@ { config, lib, ... }: -with lib; +let + inherit (lib) + mkAliasOptionModule + mkForce + mkOption + types + ; +in { options = { # A simple boolean option that can be enabled or disabled. - enable = lib.mkOption { + enable = mkOption { type = types.nullOr types.bool; default = null; example = true; @@ -41,7 +48,7 @@ with lib; # should override the next import. ( { config, lib, ... }: { - enableAlias = lib.mkForce false; + enableAlias = mkForce false; } ) diff --git a/nixpkgs/lib/tests/modules/alias-with-priority.nix b/nixpkgs/lib/tests/modules/alias-with-priority.nix index a35a06fc6974..c64a586ab2d1 100644 --- a/nixpkgs/lib/tests/modules/alias-with-priority.nix +++ b/nixpkgs/lib/tests/modules/alias-with-priority.nix @@ -6,12 +6,19 @@ { config, lib, ... }: -with lib; +let + inherit (lib) + mkAliasOptionModule + mkDefault + mkOption + types + ; +in { options = { # A simple boolean option that can be enabled or disabled. - enable = lib.mkOption { + enable = mkOption { type = types.nullOr types.bool; default = null; example = true; @@ -41,7 +48,7 @@ with lib; # should be able to be overridden by the next import. ( { config, lib, ... }: { - enableAlias = lib.mkDefault false; + enableAlias = mkDefault false; } ) diff --git a/nixpkgs/lib/tests/modules/extendModules-168767-imports.nix b/nixpkgs/lib/tests/modules/extendModules-168767-imports.nix index 489e6b5a5d83..6b50b81236d1 100644 --- a/nixpkgs/lib/tests/modules/extendModules-168767-imports.nix +++ b/nixpkgs/lib/tests/modules/extendModules-168767-imports.nix @@ -2,7 +2,14 @@ , extendModules , ... }: -with lib; + +let + inherit (lib) + mkOption + mkOverride + types + ; +in { imports = [ diff --git a/nixpkgs/lib/trivial.nix b/nixpkgs/lib/trivial.nix index c197822a4f8e..936ad207c03d 100644 --- a/nixpkgs/lib/trivial.nix +++ b/nixpkgs/lib/trivial.nix @@ -16,59 +16,114 @@ in { ## Simple (higher order) functions - /* The identity function - For when you need a function that does “nothing”. + /** + The identity function + For when you need a function that does “nothing”. - Type: id :: a -> a + + # Inputs + + `x` + + : The value to return + + # Type + + ``` + id :: a -> a + ``` */ - id = - # The value to return - x: x; + id = x: x; + + /** + The constant function + + Ignores the second argument. If called with only one argument, + constructs a function that always returns a static value. + + + # Inputs + + `x` + + : Value to return + + `y` + + : Value to ignore + + # Type + + ``` + const :: a -> b -> a + ``` - /* The constant function + # Examples + :::{.example} + ## `lib.trivial.const` usage example - Ignores the second argument. If called with only one argument, - constructs a function that always returns a static value. + ```nix + let f = const 5; in f 10 + => 5 + ``` - Type: const :: a -> b -> a - Example: - let f = const 5; in f 10 - => 5 + ::: */ const = - # Value to return x: - # Value to ignore y: x; - /* Pipes a value through a list of functions, left to right. + /** + Pipes a value through a list of functions, left to right. - Type: pipe :: a -> [<functions>] -> <return type of last function> - Example: - pipe 2 [ - (x: x + 2) # 2 + 2 = 4 - (x: x * 2) # 4 * 2 = 8 - ] - => 8 + # Inputs - # ideal to do text transformations - pipe [ "a/b" "a/c" ] [ + `value` - # create the cp command - (map (file: ''cp "${src}/${file}" $out\n'')) + : Value to start piping. - # concatenate all commands into one string - lib.concatStrings + `fns` - # make that string into a nix derivation - (pkgs.runCommand "copy-to-out" {}) + : List of functions to apply sequentially. - ] - => <drv which copies all files to $out> + # Type - The output type of each function has to be the input type - of the next function, and the last function returns the - final value. + ``` + pipe :: a -> [<functions>] -> <return type of last function> + ``` + + # Examples + :::{.example} + ## `lib.trivial.pipe` usage example + + ```nix + pipe 2 [ + (x: x + 2) # 2 + 2 = 4 + (x: x * 2) # 4 * 2 = 8 + ] + => 8 + + # ideal to do text transformations + pipe [ "a/b" "a/c" ] [ + + # create the cp command + (map (file: ''cp "${src}/${file}" $out\n'')) + + # concatenate all commands into one string + lib.concatStrings + + # make that string into a nix derivation + (pkgs.runCommand "copy-to-out" {}) + + ] + => <drv which copies all files to $out> + + The output type of each function has to be the input type + of the next function, and the last function returns the + final value. + ``` + + ::: */ pipe = builtins.foldl' (x: f: f x); @@ -79,71 +134,197 @@ in { ## Named versions corresponding to some builtin operators. - /* Concatenate two lists + /** + Concatenate two lists + + + # Inputs + + `x` + + : 1\. Function argument + + `y` + + : 2\. Function argument - Type: concat :: [a] -> [a] -> [a] + # Type - Example: - concat [ 1 2 ] [ 3 4 ] - => [ 1 2 3 4 ] + ``` + concat :: [a] -> [a] -> [a] + ``` + + # Examples + :::{.example} + ## `lib.trivial.concat` usage example + + ```nix + concat [ 1 2 ] [ 3 4 ] + => [ 1 2 3 4 ] + ``` + + ::: */ concat = x: y: x ++ y; - /* boolean “or” */ + /** + boolean “or” + + + # Inputs + + `x` + + : 1\. Function argument + + `y` + + : 2\. Function argument + */ or = x: y: x || y; - /* boolean “and” */ + /** + boolean “and” + + + # Inputs + + `x` + + : 1\. Function argument + + `y` + + : 2\. Function argument + */ and = x: y: x && y; - /* bitwise “not” */ + /** + bitwise “not” + */ bitNot = builtins.sub (-1); - /* Convert a boolean to a string. + /** + Convert a boolean to a string. + + This function uses the strings "true" and "false" to represent + boolean values. Calling `toString` on a bool instead returns "1" + and "" (sic!). + + + # Inputs + + `b` + + : 1\. Function argument - This function uses the strings "true" and "false" to represent - boolean values. Calling `toString` on a bool instead returns "1" - and "" (sic!). + # Type - Type: boolToString :: bool -> string + ``` + boolToString :: bool -> string + ``` */ boolToString = b: if b then "true" else "false"; - /* Merge two attribute sets shallowly, right side trumps left + /** + Merge two attribute sets shallowly, right side trumps left + + mergeAttrs :: attrs -> attrs -> attrs + + + # Inputs + + `x` + + : Left attribute set + + `y` + + : Right attribute set (higher precedence for equal keys) - mergeAttrs :: attrs -> attrs -> attrs - Example: - mergeAttrs { a = 1; b = 2; } { b = 3; c = 4; } - => { a = 1; b = 3; c = 4; } + # Examples + :::{.example} + ## `lib.trivial.mergeAttrs` usage example + + ```nix + mergeAttrs { a = 1; b = 2; } { b = 3; c = 4; } + => { a = 1; b = 3; c = 4; } + ``` + + ::: */ mergeAttrs = - # Left attribute set x: - # Right attribute set (higher precedence for equal keys) y: x // y; - /* Flip the order of the arguments of a binary function. + /** + Flip the order of the arguments of a binary function. + + + # Inputs + + `f` + + : 1\. Function argument + + `a` + + : 2\. Function argument - Type: flip :: (a -> b -> c) -> (b -> a -> c) + `b` - Example: - flip concat [1] [2] - => [ 2 1 ] + : 3\. Function argument + + # Type + + ``` + flip :: (a -> b -> c) -> (b -> a -> c) + ``` + + # Examples + :::{.example} + ## `lib.trivial.flip` usage example + + ```nix + flip concat [1] [2] + => [ 2 1 ] + ``` + + ::: */ flip = f: a: b: f b a; - /* Apply function if the supplied argument is non-null. + /** + Apply function if the supplied argument is non-null. + + + # Inputs - Example: - mapNullable (x: x+1) null - => null - mapNullable (x: x+1) 22 - => 23 + `f` + + : Function to call + + `a` + + : Argument to check for null before passing it to `f` + + + # Examples + :::{.example} + ## `lib.trivial.mapNullable` usage example + + ```nix + mapNullable (x: x+1) null + => null + mapNullable (x: x+1) 22 + => 23 + ``` + + ::: */ mapNullable = - # Function to call f: - # Argument to check for null before passing it to `f` a: if a == null then a else f a; # Pull in some builtins not included elsewhere. @@ -155,57 +336,84 @@ in { ## nixpkgs version strings - /* Returns the current full nixpkgs version number. */ + /** + Returns the current full nixpkgs version number. + */ version = release + versionSuffix; - /* Returns the current nixpkgs release number as string. */ + /** + Returns the current nixpkgs release number as string. + */ release = lib.strings.fileContents ./.version; - /* The latest release that is supported, at the time of release branch-off, - if applicable. + /** + The latest release that is supported, at the time of release branch-off, + if applicable. - Ideally, out-of-tree modules should be able to evaluate cleanly with all - supported Nixpkgs versions (master, release and old release until EOL). - So if possible, deprecation warnings should take effect only when all - out-of-tree expressions/libs/modules can upgrade to the new way without - losing support for supported Nixpkgs versions. + Ideally, out-of-tree modules should be able to evaluate cleanly with all + supported Nixpkgs versions (master, release and old release until EOL). + So if possible, deprecation warnings should take effect only when all + out-of-tree expressions/libs/modules can upgrade to the new way without + losing support for supported Nixpkgs versions. - This release number allows deprecation warnings to be implemented such that - they take effect as soon as the oldest release reaches end of life. */ + This release number allows deprecation warnings to be implemented such that + they take effect as soon as the oldest release reaches end of life. + */ oldestSupportedRelease = # Update on master only. Do not backport. 2311; - /* Whether a feature is supported in all supported releases (at the time of - release branch-off, if applicable). See `oldestSupportedRelease`. */ + /** + Whether a feature is supported in all supported releases (at the time of + release branch-off, if applicable). See `oldestSupportedRelease`. + + + # Inputs + + `release` + + : Release number of feature introduction as an integer, e.g. 2111 for 21.11. + Set it to the upcoming release, matching the nixpkgs/.version file. + */ isInOldestRelease = - /* Release number of feature introduction as an integer, e.g. 2111 for 21.11. - Set it to the upcoming release, matching the nixpkgs/.version file. - */ release: release <= lib.trivial.oldestSupportedRelease; - /* Returns the current nixpkgs release code name. + /** + Returns the current nixpkgs release code name. - On each release the first letter is bumped and a new animal is chosen - starting with that new letter. + On each release the first letter is bumped and a new animal is chosen + starting with that new letter. */ codeName = "Uakari"; - /* Returns the current nixpkgs version suffix as string. */ + /** + Returns the current nixpkgs version suffix as string. + */ versionSuffix = let suffixFile = ../.version-suffix; in if pathExists suffixFile then lib.strings.fileContents suffixFile else "pre-git"; - /* Attempts to return the the current revision of nixpkgs and - returns the supplied default value otherwise. + /** + Attempts to return the the current revision of nixpkgs and + returns the supplied default value otherwise. + + + # Inputs + + `default` - Type: revisionWithDefault :: string -> string + : Default value to return if revision can not be determined + + # Type + + ``` + revisionWithDefault :: string -> string + ``` */ revisionWithDefault = - # Default value to return if revision can not be determined default: let revisionFile = "${toString ./..}/.git-revision"; @@ -217,47 +425,115 @@ in { nixpkgsVersion = warn "lib.nixpkgsVersion is a deprecated alias of lib.version." version; - /* Determine whether the function is being called from inside a Nix - shell. + /** + Determine whether the function is being called from inside a Nix + shell. - Type: inNixShell :: bool + # Type + + ``` + inNixShell :: bool + ``` */ inNixShell = builtins.getEnv "IN_NIX_SHELL" != ""; - /* Determine whether the function is being called from inside pure-eval mode - by seeing whether `builtins` contains `currentSystem`. If not, we must be in - pure-eval mode. + /** + Determine whether the function is being called from inside pure-eval mode + by seeing whether `builtins` contains `currentSystem`. If not, we must be in + pure-eval mode. + + # Type - Type: inPureEvalMode :: bool + ``` + inPureEvalMode :: bool + ``` */ inPureEvalMode = ! builtins ? currentSystem; ## Integer operations - /* Return minimum of two numbers. */ + /** + Return minimum of two numbers. + + + # Inputs + + `x` + + : 1\. Function argument + + `y` + + : 2\. Function argument + */ min = x: y: if x < y then x else y; - /* Return maximum of two numbers. */ + /** + Return maximum of two numbers. + + + # Inputs + + `x` + + : 1\. Function argument + + `y` + + : 2\. Function argument + */ max = x: y: if x > y then x else y; - /* Integer modulus + /** + Integer modulus + + + # Inputs + + `base` + + : 1\. Function argument + + `int` + + : 2\. Function argument + - Example: - mod 11 10 - => 1 - mod 1 10 - => 1 + # Examples + :::{.example} + ## `lib.trivial.mod` usage example + + ```nix + mod 11 10 + => 1 + mod 1 10 + => 1 + ``` + + ::: */ mod = base: int: base - (int * (builtins.div base int)); ## Comparisons - /* C-style comparisons + /** + C-style comparisons + + a < b, compare a b => -1 + a == b, compare a b => 0 + a > b, compare a b => 1 + + + # Inputs + + `a` + + : 1\. Function argument + + `b` - a < b, compare a b => -1 - a == b, compare a b => 0 - a > b, compare a b => 1 + : 2\. Function argument */ compare = a: b: if a < b @@ -266,50 +542,100 @@ in { then 1 else 0; - /* Split type into two subtypes by predicate `p`, take all elements - of the first subtype to be less than all the elements of the - second subtype, compare elements of a single subtype with `yes` - and `no` respectively. + /** + Split type into two subtypes by predicate `p`, take all elements + of the first subtype to be less than all the elements of the + second subtype, compare elements of a single subtype with `yes` + and `no` respectively. + + + # Inputs + + `p` + + : Predicate + + `yes` + + : Comparison function if predicate holds for both values + + `no` - Type: (a -> bool) -> (a -> a -> int) -> (a -> a -> int) -> (a -> a -> int) + : Comparison function if predicate holds for neither value - Example: - let cmp = splitByAndCompare (hasPrefix "foo") compare compare; in + `a` - cmp "a" "z" => -1 - cmp "fooa" "fooz" => -1 + : First value to compare - cmp "f" "a" => 1 - cmp "fooa" "a" => -1 - # while - compare "fooa" "a" => 1 + `b` + + : Second value to compare + + # Type + + ``` + (a -> bool) -> (a -> a -> int) -> (a -> a -> int) -> (a -> a -> int) + ``` + + # Examples + :::{.example} + ## `lib.trivial.splitByAndCompare` usage example + + ```nix + let cmp = splitByAndCompare (hasPrefix "foo") compare compare; in + + cmp "a" "z" => -1 + cmp "fooa" "fooz" => -1 + + cmp "f" "a" => 1 + cmp "fooa" "a" => -1 + # while + compare "fooa" "a" => 1 + ``` + + ::: */ splitByAndCompare = - # Predicate - p: - # Comparison function if predicate holds for both values - yes: - # Comparison function if predicate holds for neither value - no: - # First value to compare - a: - # Second value to compare - b: + p: yes: no: a: b: if p a then if p b then yes a b else -1 else if p b then 1 else no a b; - /* Reads a JSON file. + /** + Reads a JSON file. - Type: importJSON :: path -> any + + # Inputs + + `path` + + : 1\. Function argument + + # Type + + ``` + importJSON :: path -> any + ``` */ importJSON = path: builtins.fromJSON (builtins.readFile path); - /* Reads a TOML file. + /** + Reads a TOML file. + + + # Inputs - Type: importTOML :: path -> any + `path` + + : 1\. Function argument + + # Type + + ``` + importTOML :: path -> any + ``` */ importTOML = path: builtins.fromTOML (builtins.readFile path); @@ -329,7 +655,7 @@ in { # TODO: figure out a clever way to integrate location information from # something like __unsafeGetAttrPos. - /* + /** Print a warning before returning the second argument. This function behaves like `builtins.trace`, but requires a string message and formats it as a warning, including the `warning: ` prefix. @@ -337,28 +663,80 @@ in { To get a call stack trace and abort evaluation, set the environment variable `NIX_ABORT_ON_WARN=true` and set the Nix options `--option pure-eval false --show-trace` - Type: string -> a -> a + # Inputs + + `msg` + + : Warning message to print. + + `val` + + : Value to return as-is. + + # Type + + ``` + string -> a -> a + ``` */ warn = if lib.elem (builtins.getEnv "NIX_ABORT_ON_WARN") ["1" "true" "yes"] then msg: builtins.trace "[1;31mwarning: ${msg}[0m" (abort "NIX_ABORT_ON_WARN=true; warnings are treated as unrecoverable errors.") else msg: builtins.trace "[1;31mwarning: ${msg}[0m"; - /* + /** Like warn, but only warn when the first argument is `true`. - Type: bool -> string -> a -> a + + # Inputs + + `cond` + + : 1\. Function argument + + `msg` + + : 2\. Function argument + + `val` + + : Value to return as-is. + + # Type + + ``` + bool -> string -> a -> a + ``` */ warnIf = cond: msg: if cond then warn msg else x: x; - /* + /** Like warnIf, but negated (warn if the first argument is `false`). - Type: bool -> string -> a -> a + + # Inputs + + `cond` + + : 1\. Function argument + + `msg` + + : 2\. Function argument + + `val` + + : Value to return as-is. + + # Type + + ``` + bool -> string -> a -> a + ``` */ warnIfNot = cond: msg: if cond then x: x else warn msg; - /* + /** Like the `assert b; e` expression, but with a custom error message and without the semicolon. @@ -369,33 +747,95 @@ in { Calls can be juxtaposed using function application, as `(r: r) a = a`, so `(r: r) (r: r) a = a`, and so forth. - Type: bool -> string -> a -> a - Example: + # Inputs + + `cond` + + : 1\. Function argument - throwIfNot (lib.isList overlays) "The overlays argument to nixpkgs must be a list." - lib.foldr (x: throwIfNot (lib.isFunction x) "All overlays passed to nixpkgs must be functions.") (r: r) overlays - pkgs + `msg` + : 2\. Function argument + + # Type + + ``` + bool -> string -> a -> a + ``` + + # Examples + :::{.example} + ## `lib.trivial.throwIfNot` usage example + + ```nix + throwIfNot (lib.isList overlays) "The overlays argument to nixpkgs must be a list." + lib.foldr (x: throwIfNot (lib.isFunction x) "All overlays passed to nixpkgs must be functions.") (r: r) overlays + pkgs + ``` + + ::: */ throwIfNot = cond: msg: if cond then x: x else throw msg; - /* + /** Like throwIfNot, but negated (throw if the first argument is `true`). - Type: bool -> string -> a -> a + + # Inputs + + `cond` + + : 1\. Function argument + + `msg` + + : 2\. Function argument + + # Type + + ``` + bool -> string -> a -> a + ``` */ throwIf = cond: msg: if cond then throw msg else x: x; - /* Check if the elements in a list are valid values from a enum, returning the identity function, or throwing an error message otherwise. + /** + Check if the elements in a list are valid values from a enum, returning the identity function, or throwing an error message otherwise. + + + # Inputs + + `msg` - Example: - let colorVariants = ["bright" "dark" "black"] - in checkListOfEnum "color variants" [ "standard" "light" "dark" ] colorVariants; - => - error: color variants: bright, black unexpected; valid ones: standard, light, dark + : 1\. Function argument - Type: String -> List ComparableVal -> List ComparableVal -> a -> a + `valid` + + : 2\. Function argument + + `given` + + : 3\. Function argument + + # Type + + ``` + String -> List ComparableVal -> List ComparableVal -> a -> a + ``` + + # Examples + :::{.example} + ## `lib.trivial.checkListOfEnum` usage example + + ```nix + let colorVariants = ["bright" "dark" "black"] + in checkListOfEnum "color variants" [ "standard" "light" "dark" ] colorVariants; + => + error: color variants: bright, black unexpected; valid ones: standard, light, dark + ``` + + ::: */ checkListOfEnum = msg: valid: given: let @@ -410,15 +850,27 @@ in { ## Function annotations - /* Add metadata about expected function arguments to a function. - The metadata should match the format given by - builtins.functionArgs, i.e. a set from expected argument to a bool - representing whether that argument has a default or not. - setFunctionArgs : (a → b) → Map String Bool → (a → b) + /** + Add metadata about expected function arguments to a function. + The metadata should match the format given by + builtins.functionArgs, i.e. a set from expected argument to a bool + representing whether that argument has a default or not. + setFunctionArgs : (a → b) → Map String Bool → (a → b) - This function is necessary because you can't dynamically create a - function of the { a, b ? foo, ... }: format, but some facilities - like callPackage expect to be able to query expected arguments. + This function is necessary because you can't dynamically create a + function of the { a, b ? foo, ... }: format, but some facilities + like callPackage expect to be able to query expected arguments. + + + # Inputs + + `f` + + : 1\. Function argument + + `args` + + : 2\. Function argument */ setFunctionArgs = f: args: { # TODO: Should we add call-time "type" checking like built in? @@ -426,84 +878,133 @@ in { __functionArgs = args; }; - /* Extract the expected function arguments from a function. - This works both with nix-native { a, b ? foo, ... }: style - functions and functions with args set with 'setFunctionArgs'. It - has the same return type and semantics as builtins.functionArgs. - setFunctionArgs : (a → b) → Map String Bool. + /** + Extract the expected function arguments from a function. + This works both with nix-native { a, b ? foo, ... }: style + functions and functions with args set with 'setFunctionArgs'. It + has the same return type and semantics as builtins.functionArgs. + setFunctionArgs : (a → b) → Map String Bool. + + + # Inputs + + `f` + + : 1\. Function argument */ functionArgs = f: if f ? __functor then f.__functionArgs or (functionArgs (f.__functor f)) else builtins.functionArgs f; - /* Check whether something is a function or something - annotated with function args. + /** + Check whether something is a function or something + annotated with function args. + + + # Inputs + + `f` + + : 1\. Function argument */ isFunction = f: builtins.isFunction f || (f ? __functor && isFunction (f.__functor f)); - /* + /** `mirrorFunctionArgs f g` creates a new function `g'` with the same behavior as `g` (`g' x == g x`) but its function arguments mirroring `f` (`lib.functionArgs g' == lib.functionArgs f`). - Type: - mirrorFunctionArgs :: (a -> b) -> (a -> c) -> (a -> c) - - Example: - addab = {a, b}: a + b - addab { a = 2; b = 4; } - => 6 - lib.functionArgs addab - => { a = false; b = false; } - addab1 = attrs: addab attrs + 1 - addab1 { a = 2; b = 4; } - => 7 - lib.functionArgs addab1 - => { } - addab1' = lib.mirrorFunctionArgs addab addab1 - addab1' { a = 2; b = 4; } - => 7 - lib.functionArgs addab1' - => { a = false; b = false; } + + # Inputs + + `f` + + : Function to provide the argument metadata + + `g` + + : Function to set the argument metadata to + + # Type + + ``` + mirrorFunctionArgs :: (a -> b) -> (a -> c) -> (a -> c) + ``` + + # Examples + :::{.example} + ## `lib.trivial.mirrorFunctionArgs` usage example + + ```nix + addab = {a, b}: a + b + addab { a = 2; b = 4; } + => 6 + lib.functionArgs addab + => { a = false; b = false; } + addab1 = attrs: addab attrs + 1 + addab1 { a = 2; b = 4; } + => 7 + lib.functionArgs addab1 + => { } + addab1' = lib.mirrorFunctionArgs addab addab1 + addab1' { a = 2; b = 4; } + => 7 + lib.functionArgs addab1' + => { a = false; b = false; } + ``` + + ::: */ mirrorFunctionArgs = - # Function to provide the argument metadata f: let fArgs = functionArgs f; in - # Function to set the argument metadata to g: setFunctionArgs g fArgs; - /* + /** Turns any non-callable values into constant functions. Returns callable values as is. - Example: - nix-repl> lib.toFunction 1 2 - 1 + # Inputs + + `v` + + : Any value + + + # Examples + :::{.example} + ## `lib.trivial.toFunction` usage example + + ```nix + nix-repl> lib.toFunction 1 2 + 1 - nix-repl> lib.toFunction (x: x + 1) 2 - 3 + nix-repl> lib.toFunction (x: x + 1) 2 + 3 + ``` + + ::: */ toFunction = - # Any value v: if isFunction v then v else k: v; - /* Convert the given positive integer to a string of its hexadecimal - representation. For example: + /** + Convert the given positive integer to a string of its hexadecimal + representation. For example: - toHexString 0 => "0" + toHexString 0 => "0" - toHexString 16 => "10" + toHexString 16 => "10" - toHexString 250 => "FA" + toHexString 250 => "FA" */ toHexString = let hexDigits = { @@ -520,14 +1021,26 @@ in { else hexDigits.${toString d}; in i: lib.concatMapStrings toHexDigit (toBaseDigits 16 i); - /* `toBaseDigits base i` converts the positive integer i to a list of its - digits in the given base. For example: + /** + `toBaseDigits base i` converts the positive integer i to a list of its + digits in the given base. For example: + + toBaseDigits 10 123 => [ 1 2 3 ] + + toBaseDigits 2 6 => [ 1 1 0 ] + + toBaseDigits 16 250 => [ 15 10 ] + + + # Inputs + + `base` - toBaseDigits 10 123 => [ 1 2 3 ] + : 1\. Function argument - toBaseDigits 2 6 => [ 1 1 0 ] + `i` - toBaseDigits 16 250 => [ 15 10 ] + : 2\. Function argument */ toBaseDigits = base: i: let |