Merge pull request #97133 from Infinisil/improved-toPretty
Improve `generators.toPretty`
This commit is contained in:
commit
366a677dbb
|
@ -203,40 +203,59 @@ rec {
|
||||||
/* If this option is true, attrsets like { __pretty = fn; val = …; }
|
/* If this option is true, attrsets like { __pretty = fn; val = …; }
|
||||||
will use fn to convert val to a pretty printed representation.
|
will use fn to convert val to a pretty printed representation.
|
||||||
(This means fn is type Val -> String.) */
|
(This means fn is type Val -> String.) */
|
||||||
allowPrettyValues ? false
|
allowPrettyValues ? false,
|
||||||
}@args: v: with builtins;
|
/* 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;
|
||||||
let isPath = v: typeOf v == "path";
|
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 isInt v then toString v
|
||||||
else if isFloat v then "~${toString v}"
|
else if isFloat v then "~${toString v}"
|
||||||
else if isString v then ''"${libStr.escape [''"''] v}"''
|
else if isString v then
|
||||||
|
let
|
||||||
|
# Separate a string into its lines
|
||||||
|
newlineSplits = filter (v: ! isList v) (builtins.split "\n" v);
|
||||||
|
# For a '' string terminated by a \n, which happens when the closing '' is on a new line
|
||||||
|
multilineResult = "''" + introSpace + concatStringsSep introSpace (lib.init newlineSplits) + outroSpace + "''";
|
||||||
|
# For a '' string not terminated by a \n, which happens when the closing '' is not on a new line
|
||||||
|
multilineResult' = "''" + introSpace + concatStringsSep introSpace newlineSplits + "''";
|
||||||
|
# For single lines, replace all newlines with their escaped representation
|
||||||
|
singlelineResult = "\"" + libStr.escape [ "\"" ] (concatStringsSep "\\n" newlineSplits) + "\"";
|
||||||
|
in if multiline && length newlineSplits > 1 then
|
||||||
|
if lib.last newlineSplits == "" then multilineResult else multilineResult'
|
||||||
|
else singlelineResult
|
||||||
else if true == v then "true"
|
else if true == v then "true"
|
||||||
else if false == v then "false"
|
else if false == v then "false"
|
||||||
else if null == v then "null"
|
else if null == v then "null"
|
||||||
else if isPath v then toString v
|
else if isPath v then toString v
|
||||||
else if isList v then "[ "
|
else if isList v then
|
||||||
+ libStr.concatMapStringsSep " " (toPretty args) v
|
if v == [] then "[ ]"
|
||||||
+ " ]"
|
else "[" + introSpace
|
||||||
|
+ libStr.concatMapStringsSep introSpace (go (indent + " ")) v
|
||||||
|
+ outroSpace + "]"
|
||||||
|
else if isFunction v then
|
||||||
|
let fna = lib.functionArgs v;
|
||||||
|
showFnas = concatStringsSep ", " (libAttr.mapAttrsToList
|
||||||
|
(name: hasDefVal: if hasDefVal then name + "?" else name)
|
||||||
|
fna);
|
||||||
|
in if fna == {} then "<function>"
|
||||||
|
else "<function, args: {${showFnas}}>"
|
||||||
else if isAttrs v then
|
else if isAttrs v then
|
||||||
# apply pretty values if allowed
|
# apply pretty values if allowed
|
||||||
if attrNames v == [ "__pretty" "val" ] && allowPrettyValues
|
if attrNames v == [ "__pretty" "val" ] && allowPrettyValues
|
||||||
then v.__pretty v.val
|
then v.__pretty v.val
|
||||||
# TODO: there is probably a better representation?
|
else if v == {} then "{ }"
|
||||||
else if v ? type && v.type == "derivation" then
|
else if v ? type && v.type == "derivation" then
|
||||||
"<δ:${v.name}>"
|
"<derivation ${v.drvPath}>"
|
||||||
# "<δ:${concatStringsSep "," (builtins.attrNames v)}>"
|
else "{" + introSpace
|
||||||
else "{ "
|
+ libStr.concatStringsSep introSpace (libAttr.mapAttrsToList
|
||||||
+ libStr.concatStringsSep " " (libAttr.mapAttrsToList
|
|
||||||
(name: value:
|
(name: value:
|
||||||
"${toPretty args name} = ${toPretty args value};") v)
|
"${libStr.escapeNixIdentifier name} = ${go (indent + " ") value};") v)
|
||||||
+ " }"
|
+ outroSpace + "}"
|
||||||
else if isFunction v then
|
|
||||||
let fna = lib.functionArgs v;
|
|
||||||
showFnas = concatStringsSep "," (libAttr.mapAttrsToList
|
|
||||||
(name: hasDefVal: if hasDefVal then "(${name})" else name)
|
|
||||||
fna);
|
|
||||||
in if fna == {} then "<λ>"
|
|
||||||
else "<λ:{${showFnas}}>"
|
|
||||||
else abort "generators.toPretty: should never happen (v = ${v})";
|
else abort "generators.toPretty: should never happen (v = ${v})";
|
||||||
|
in go "";
|
||||||
|
|
||||||
# PLIST handling
|
# PLIST handling
|
||||||
toPlist = {}: v: let
|
toPlist = {}: v: let
|
||||||
|
|
|
@ -445,32 +445,90 @@ runTests {
|
||||||
expected = builtins.toJSON val;
|
expected = builtins.toJSON val;
|
||||||
};
|
};
|
||||||
|
|
||||||
testToPretty = {
|
testToPretty =
|
||||||
expr = mapAttrs (const (generators.toPretty {})) rec {
|
let
|
||||||
|
deriv = derivation { name = "test"; builder = "/bin/sh"; system = builtins.currentSystem; };
|
||||||
|
in {
|
||||||
|
expr = mapAttrs (const (generators.toPretty { multiline = false; })) rec {
|
||||||
int = 42;
|
int = 42;
|
||||||
float = 0.1337;
|
float = 0.1337;
|
||||||
bool = true;
|
bool = true;
|
||||||
|
emptystring = "";
|
||||||
string = ''fno"rd'';
|
string = ''fno"rd'';
|
||||||
|
newlinestring = "\n";
|
||||||
path = /. + "/foo";
|
path = /. + "/foo";
|
||||||
null_ = null;
|
null_ = null;
|
||||||
function = x: x;
|
function = x: x;
|
||||||
functionArgs = { arg ? 4, foo }: arg;
|
functionArgs = { arg ? 4, foo }: arg;
|
||||||
list = [ 3 4 function [ false ] ];
|
list = [ 3 4 function [ false ] ];
|
||||||
|
emptylist = [];
|
||||||
attrs = { foo = null; "foo bar" = "baz"; };
|
attrs = { foo = null; "foo bar" = "baz"; };
|
||||||
drv = derivation { name = "test"; system = builtins.currentSystem; };
|
emptyattrs = {};
|
||||||
|
drv = deriv;
|
||||||
};
|
};
|
||||||
expected = rec {
|
expected = rec {
|
||||||
int = "42";
|
int = "42";
|
||||||
float = "~0.133700";
|
float = "~0.133700";
|
||||||
bool = "true";
|
bool = "true";
|
||||||
|
emptystring = ''""'';
|
||||||
string = ''"fno\"rd"'';
|
string = ''"fno\"rd"'';
|
||||||
|
newlinestring = "\"\\n\"";
|
||||||
path = "/foo";
|
path = "/foo";
|
||||||
null_ = "null";
|
null_ = "null";
|
||||||
function = "<λ>";
|
function = "<function>";
|
||||||
functionArgs = "<λ:{(arg),foo}>";
|
functionArgs = "<function, args: {arg?, foo}>";
|
||||||
list = "[ 3 4 ${function} [ false ] ]";
|
list = "[ 3 4 ${function} [ false ] ]";
|
||||||
attrs = "{ \"foo\" = null; \"foo bar\" = \"baz\"; }";
|
emptylist = "[ ]";
|
||||||
drv = "<δ:test>";
|
attrs = "{ foo = null; \"foo bar\" = \"baz\"; }";
|
||||||
|
emptyattrs = "{ }";
|
||||||
|
drv = "<derivation ${deriv.drvPath}>";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testToPrettyMultiline = {
|
||||||
|
expr = mapAttrs (const (generators.toPretty { })) rec {
|
||||||
|
list = [ 3 4 [ false ] ];
|
||||||
|
attrs = { foo = null; bar.foo = "baz"; };
|
||||||
|
newlinestring = "\n";
|
||||||
|
multilinestring = ''
|
||||||
|
hello
|
||||||
|
there
|
||||||
|
test
|
||||||
|
'';
|
||||||
|
multilinestring' = ''
|
||||||
|
hello
|
||||||
|
there
|
||||||
|
test'';
|
||||||
|
};
|
||||||
|
expected = rec {
|
||||||
|
list = ''
|
||||||
|
[
|
||||||
|
3
|
||||||
|
4
|
||||||
|
[
|
||||||
|
false
|
||||||
|
]
|
||||||
|
]'';
|
||||||
|
attrs = ''
|
||||||
|
{
|
||||||
|
bar = {
|
||||||
|
foo = "baz";
|
||||||
|
};
|
||||||
|
foo = null;
|
||||||
|
}'';
|
||||||
|
newlinestring = "''\n \n''";
|
||||||
|
multilinestring = ''
|
||||||
|
'''
|
||||||
|
hello
|
||||||
|
there
|
||||||
|
test
|
||||||
|
''''';
|
||||||
|
multilinestring' = ''
|
||||||
|
'''
|
||||||
|
hello
|
||||||
|
there
|
||||||
|
test''''';
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue