mirror of
https://github.com/ilyakooo0/nixpkgs.git
synced 2024-12-27 22:03:54 +03:00
lib/generators: move limit detection into withRecursion
As suggested in #131205. Now it's possible to pretty-print a value with `lib.generators` like this: with lib.generators; toPretty { } (withRecursion { depthLimit = 10; } /* arbitrarily complex value */) Also, this can be used for any other pretty-printer now if needed.
This commit is contained in:
parent
b6d3c9f821
commit
5773ae93f7
@ -195,6 +195,30 @@ rec {
|
|||||||
*/
|
*/
|
||||||
toYAML = {}@args: toJSON args;
|
toYAML = {}@args: toJSON args;
|
||||||
|
|
||||||
|
withRecursion =
|
||||||
|
args@{
|
||||||
|
/* If this option is not null, `toPretty` will stop evaluating at a certain depth */
|
||||||
|
depthLimit
|
||||||
|
/* If this option is true, an error will be thrown, if a certain given depth is exceeded */
|
||||||
|
, throwOnDepthLimit ? true
|
||||||
|
}:
|
||||||
|
assert builtins.isInt depthLimit;
|
||||||
|
let
|
||||||
|
transform = depth:
|
||||||
|
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.withRecursion'!"
|
||||||
|
else const "<unevaluated>"
|
||||||
|
else id;
|
||||||
|
mapAny = with builtins; depth: v:
|
||||||
|
let
|
||||||
|
evalNext = x: mapAny (depth + 1) (transform (depth + 1) x);
|
||||||
|
in
|
||||||
|
if isAttrs v then mapAttrs (const evalNext) v
|
||||||
|
else if isList v then map evalNext v
|
||||||
|
else transform (depth + 1) v;
|
||||||
|
in
|
||||||
|
mapAny 0;
|
||||||
|
|
||||||
/* Pretty print a value, akin to `builtins.trace`.
|
/* Pretty print a value, akin to `builtins.trace`.
|
||||||
* Should probably be a builtin as well.
|
* Should probably be a builtin as well.
|
||||||
@ -205,23 +229,14 @@ rec {
|
|||||||
(This means fn is type Val -> String.) */
|
(This means fn is type Val -> String.) */
|
||||||
allowPrettyValues ? false,
|
allowPrettyValues ? false,
|
||||||
/* If this option is true, the output is indented with newlines for attribute sets and lists */
|
/* If this option is true, the output is indented with newlines for attribute sets and lists */
|
||||||
multiline ? true,
|
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:
|
}@args:
|
||||||
assert depthLimit != null -> builtins.isInt depthLimit;
|
|
||||||
assert throwOnDepthLimit -> depthLimit != null;
|
|
||||||
let
|
let
|
||||||
go = depth: indent: v: with builtins;
|
go = indent: v: with builtins;
|
||||||
let isPath = v: typeOf v == "path";
|
let isPath = v: typeOf v == "path";
|
||||||
introSpace = if multiline then "\n${indent} " else " ";
|
introSpace = if multiline then "\n${indent} " else " ";
|
||||||
outroSpace = if multiline then "\n${indent}" else " ";
|
outroSpace = if multiline then "\n${indent}" else " ";
|
||||||
in if depthLimit != null && depth > depthLimit then
|
in if isInt v then toString v
|
||||||
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 isFloat v then "~${toString v}"
|
||||||
else if isString v then
|
else if isString v then
|
||||||
let
|
let
|
||||||
@ -243,7 +258,7 @@ rec {
|
|||||||
else if isList v then
|
else if isList v then
|
||||||
if v == [] then "[ ]"
|
if v == [] then "[ ]"
|
||||||
else "[" + introSpace
|
else "[" + introSpace
|
||||||
+ libStr.concatMapStringsSep introSpace (go (depth + 1) (indent + " ")) v
|
+ libStr.concatMapStringsSep introSpace (go (indent + " ")) v
|
||||||
+ outroSpace + "]"
|
+ outroSpace + "]"
|
||||||
else if isFunction v then
|
else if isFunction v then
|
||||||
let fna = lib.functionArgs v;
|
let fna = lib.functionArgs v;
|
||||||
@ -262,10 +277,10 @@ rec {
|
|||||||
else "{" + introSpace
|
else "{" + introSpace
|
||||||
+ libStr.concatStringsSep introSpace (libAttr.mapAttrsToList
|
+ libStr.concatStringsSep introSpace (libAttr.mapAttrsToList
|
||||||
(name: value:
|
(name: value:
|
||||||
"${libStr.escapeNixIdentifier name} = ${go (depth + 1) (indent + " ") value};") v)
|
"${libStr.escapeNixIdentifier name} = ${go (indent + " ") value};") v)
|
||||||
+ outroSpace + "}"
|
+ outroSpace + "}"
|
||||||
else abort "generators.toPretty: should never happen (v = ${v})";
|
else abort "generators.toPretty: should never happen (v = ${v})";
|
||||||
in go 0 "";
|
in go "";
|
||||||
|
|
||||||
# PLIST handling
|
# PLIST handling
|
||||||
toPlist = {}: v: let
|
toPlist = {}: v: let
|
||||||
|
@ -247,7 +247,9 @@ rec {
|
|||||||
showDefs = defs: concatMapStrings (def:
|
showDefs = defs: concatMapStrings (def:
|
||||||
let
|
let
|
||||||
# Pretty print the value for display, if successful
|
# Pretty print the value for display, if successful
|
||||||
prettyEval = builtins.tryEval (lib.generators.toPretty { depthLimit = 10; } def.value);
|
prettyEval = builtins.tryEval
|
||||||
|
(lib.generators.toPretty { }
|
||||||
|
(lib.generators.withRecursion { depthLimit = 10; throwOnDepthLimit = false; } def.value));
|
||||||
# Split it into its lines
|
# Split it into its lines
|
||||||
lines = filter (v: ! isList v) (builtins.split "\n" prettyEval.value);
|
lines = filter (v: ! isList v) (builtins.split "\n" prettyEval.value);
|
||||||
# Only display the first 5 lines, and indent them for better visibility
|
# Only display the first 5 lines, and indent them for better visibility
|
||||||
|
@ -534,8 +534,8 @@ runTests {
|
|||||||
a.b = 1;
|
a.b = 1;
|
||||||
a.c = a;
|
a.c = a;
|
||||||
in {
|
in {
|
||||||
expr = generators.toPretty { depthLimit = 2; } a;
|
expr = generators.toPretty { } (generators.withRecursion { throwOnDepthLimit = false; depthLimit = 2; } a);
|
||||||
expected = "{\n b = 1;\n c = {\n b = 1;\n c = {\n b = <unevaluated>;\n c = <unevaluated>;\n };\n };\n}";
|
expected = "{\n b = 1;\n c = {\n b = \"<unevaluated>\";\n c = {\n b = \"<unevaluated>\";\n c = \"<unevaluated>\";\n };\n };\n}";
|
||||||
};
|
};
|
||||||
|
|
||||||
testToPrettyLimitThrow =
|
testToPrettyLimitThrow =
|
||||||
@ -543,7 +543,8 @@ runTests {
|
|||||||
a.b = 1;
|
a.b = 1;
|
||||||
a.c = a;
|
a.c = a;
|
||||||
in {
|
in {
|
||||||
expr = (builtins.tryEval (generators.toPretty { depthLimit = 2; throwOnDepthLimit = true; } a)).success;
|
expr = (builtins.tryEval
|
||||||
|
(generators.toPretty { } (generators.withRecursion { depthLimit = 2; } a))).success;
|
||||||
expected = false;
|
expected = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user