diff --git a/lib/generators.nix b/lib/generators.nix index 4d3c920b0ae3..0e5ce864356a 100644 --- a/lib/generators.nix +++ b/lib/generators.nix @@ -90,4 +90,36 @@ rec { * parsers as well. */ toYAML = {}@args: toJSON args; + + # TODO we need some kind of pattern matching sometimes + /* Pretty print a value, akin to `builtins.trace`. + * Should probably be a builtin as well. + */ + toPretty = { + /* If this option is true, attrsets like { __pretty = fn; val = …; } + will use fn to convert val to a pretty printed representation. + (This means fn is type Val -> String.) */ + allowPrettyValues ? false + }@args: v: with builtins; + if isInt v then toString v + else if isBool v then (if v == true then "true" else "false") + else if isString v then "\"" + v + "\"" + else if null == v then "null" + else if isFunction v then "<λ>" + else if isList v then "[ " + + libStr.concatMapStringsSep " " (toPretty args) v + + " ]" + else if isAttrs v then + # apply pretty values if allowed + if attrNames v == [ "__pretty" "val" ] && allowPrettyValues + then v.__pretty v.val + # TODO: there is probably a better representation? + else if v ? type && v.type == "derivation" then "<δ>" + else "{ " + + libStr.concatStringsSep " " (libAttr.mapAttrsToList + (name: value: + "${toPretty args name} = ${toPretty args value};") v) + + " }" + else "toPretty: should never happen (v = ${v})"; + } diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index 22557bdfeefb..f40036274e81 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -285,6 +285,36 @@ runTests { expected = builtins.toJSON val; }; + testToPretty = { + expr = mapAttrs (const (generators.toPretty {})) rec { + int = 42; + bool = true; + string = "fnord"; + null_ = null; + function = x: x; + list = [ 3 4 function [ false ] ]; + attrs = { foo = null; "foo bar" = "baz"; }; + drv = derivation { name = "test"; system = builtins.currentSystem; }; + }; + expected = rec { + int = "42"; + bool = "true"; + string = "\"fnord\""; + null_ = "null"; + function = "<λ>"; + list = "[ 3 4 ${function} [ false ] ]"; + attrs = "{ \"foo\" = null; \"foo bar\" = \"baz\"; }"; + drv = "<δ>"; + }; + }; + + testToPrettyAllowPrettyValues = { + expr = generators.toPretty { allowPrettyValues = true; } + { __pretty = v: "«" + v + "»"; val = "foo"; }; + expected = "«foo»"; + }; + + # MISC testOverridableDelayableArgsTest = {