From eda04ce64e5abb1c9ac4a8b3484d1e7e25a51f51 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Tue, 21 Oct 2025 10:48:13 +0200 Subject: [PATCH] docs: improve docs for 'lib.attrsets.recursiveUpdateUntil' --- lib/attrsets.nix | 51 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/lib/attrsets.nix b/lib/attrsets.nix index b05f8a2f867e8..0e79a3b5a39b6 100644 --- a/lib/attrsets.nix +++ b/lib/attrsets.nix @@ -1628,26 +1628,43 @@ 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. + Update `lhs` so that `rhs` wins for any given attribute path that occurs in both. + + Unlike the `//` (update) operator, which operates on a single attribute set, + This function views its operands `lhs` and `rhs` as a mapping from attribute *paths* + to values. + + The caller-provided function `pred` decides whether any given path is one of the following: + + - `true`: a value in the mapping + - `false`: an attribute set whose purpose is to create the nesting structure. # 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. + : Predicate function (of type `List String -> Any -> Any -> Bool`) + + Inputs: + + - `path : List String`: the path to the current attribute as a list of strings for attribute names + - `lhsAtPath : Any`: the value at that path in `lhs`; same as `getAttrFromPath path lhs` + - `rhsAtPath : Any`: the value at that path in `rhs`; same as `getAttrFromPath path rhs` + + Output: + + - `true`: `path` points to a value in the mapping, and `rhsAtPath` will appear in the return value of `recursiveUpdateUntil` + - `false`: `path` is part of the nesting structure and will be an attrset in the return value of `recursiveUpdateUntil` + + `pred` is only called for `path`s that extend prefixes for which `pred` returned `false`. `lhs` - : Left attribute set of the merge. + : Left attribute set of the update. `rhs` - : Right attribute set of the merge. + : Right attribute set of the update. # Type @@ -1660,23 +1677,23 @@ rec { ## `lib.attrsets.recursiveUpdateUntil` usage example ```nix - recursiveUpdateUntil (path: l: r: path == ["foo"]) { - # first attribute set + recursiveUpdateUntil (path: lhs: rhs: path == ["foo"]) { + # left attribute set foo.bar = 1; foo.baz = 2; bar = 3; } { - #second attribute set + # right attribute set foo.bar = 1; foo.quz = 2; baz = 4; } => { - foo.bar = 1; # 'foo.*' from the second set + foo.bar = 1; # 'foo.*' from the 'right' set foo.quz = 2; # - bar = 3; # 'bar' from the first set - baz = 4; # 'baz' from the second set + bar = 3; # 'bar' from the 'left' set + baz = 4; # 'baz' from the 'right' set } ``` @@ -1688,9 +1705,9 @@ rec { f = attrPath: zipAttrsWith ( - n: values: + name: values: let - here = attrPath ++ [ n ]; + here = attrPath ++ [ name ]; in if length values == 1 || pred here (elemAt values 1) (head values) then head values