{ lib }:
with lib;
let
attrFilter = name: value: name != "_module" && value != null;
in
rec {
toPLIST = x: ''
'' + pprExpr "" x
+ "\n";
pprExpr = ind: x:
if isNull x then "" else
if isBool x then pprBool ind x else
if isInt x then pprInt ind x else
if isString x then pprStr ind x else
if isList x then pprList ind x else
if isAttrs x then pprAttrs ind x else
throw "invalid plist type";
pprLiteral = ind: x: ind + x;
pprBool = ind: x: pprLiteral ind (if x then "" else "");
pprInt = ind: x: pprLiteral ind "${toString x}";
pprStr = ind: x: pprLiteral ind "${x}";
pprKey = ind: x: pprLiteral ind "${x}";
pprIndent = ind: (pprExpr "\t${ind}");
pprItem = ind: concatMapStringsSep "\n" (pprIndent ind);
pprList = ind: x: concatStringsSep "\n" [
(pprLiteral ind "")
(pprItem ind x)
(pprLiteral ind "")
];
pprAttrs = ind: x: concatStringsSep "\n" [
(pprLiteral ind "")
(pprAttr ind x)
(pprLiteral ind "")
];
pprAttr = ind: x: concatStringsSep "\n" (flatten (mapAttrsToList (name: value: optional (attrFilter name value) [
(pprKey "\t${ind}" name)
(pprExpr "\t${ind}" value)
]) x));
}