diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/generators.nix | 24 | ||||
-rw-r--r-- | lib/tests/misc.nix | 18 |
2 files changed, 35 insertions, 7 deletions
diff --git a/lib/generators.nix b/lib/generators.nix index bcb0f371a9b51..b1639b677f65d 100644 --- a/lib/generators.nix +++ b/lib/generators.nix @@ -205,13 +205,23 @@ rec { (This means fn is type Val -> String.) */ allowPrettyValues ? false, /* If this option is true, the output is indented with newlines for attribute sets and lists */ - multiline ? true - }@args: let - go = indent: v: with builtins; + multiline ? true, + /* If this option is not null, `toPretty` will stop evaluating at a certain depth */ + depthLimit ? null, + /* If this option is true, an error will be thrown, if a certain given depth is exceeded */ + throwOnDepthLimit ? false + }@args: + assert depthLimit != null -> builtins.isInt depthLimit; + assert throwOnDepthLimit -> depthLimit != null; + let + go = depth: indent: v: with builtins; let isPath = v: typeOf v == "path"; introSpace = if multiline then "\n${indent} " else " "; outroSpace = if multiline then "\n${indent}" else " "; - in if isInt v then toString v + in if depthLimit != null && depth > depthLimit then + if throwOnDepthLimit then throw "Exceeded maximum eval-depth limit of ${toString depthLimit} while trying to pretty-print with `generators.toPretty'!" + else "<unevaluated>" + else if isInt v then toString v else if isFloat v then "~${toString v}" else if isString v then let @@ -233,7 +243,7 @@ rec { else if isList v then if v == [] then "[ ]" else "[" + introSpace - + libStr.concatMapStringsSep introSpace (go (indent + " ")) v + + libStr.concatMapStringsSep introSpace (go (depth + 1) (indent + " ")) v + outroSpace + "]" else if isFunction v then let fna = lib.functionArgs v; @@ -252,10 +262,10 @@ rec { else "{" + introSpace + libStr.concatStringsSep introSpace (libAttr.mapAttrsToList (name: value: - "${libStr.escapeNixIdentifier name} = ${go (indent + " ") value};") v) + "${libStr.escapeNixIdentifier name} = ${go (depth + 1) (indent + " ") value};") v) + outroSpace + "}" else abort "generators.toPretty: should never happen (v = ${v})"; - in go ""; + in go 0 ""; # PLIST handling toPlist = {}: v: let diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index 4b2e5afc1d609..110716ca69132 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -529,6 +529,24 @@ runTests { }; }; + testToPrettyLimit = + let + a.b = 1; + a.c = a; + in { + expr = generators.toPretty { depthLimit = 2; } a; + expected = "{\n b = 1;\n c = {\n b = 1;\n c = {\n b = <unevaluated>;\n c = <unevaluated>;\n };\n };\n}"; + }; + + testToPrettyLimitThrow = + let + a.b = 1; + a.c = a; + in { + expr = (builtins.tryEval (generators.toPretty { depthLimit = 2; throwOnDepthLimit = true; } a)).success; + expected = false; + }; + testToPrettyMultiline = { expr = mapAttrs (const (generators.toPretty { })) rec { list = [ 3 4 [ false ] ]; |