diff --git a/lib/generators.nix b/lib/generators.nix
index c09384c00f5..aab4498f9c6 100644
--- a/lib/generators.nix
+++ b/lib/generators.nix
@@ -175,4 +175,52 @@ rec {
else "<λ:{${showFnas}}>"
else abort "toPretty: should never happen (v = ${v})";
+ # PLIST handling
+
+ toPLIST = x: ''
+
+
+
+ '' + pprExpr "" x
+ + "\n";
+
+ pprExpr = ind: x: with builtins;
+ 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: libStr.concatMapStringsSep "\n" (pprIndent ind);
+
+ pprList = ind: x: libStr.concatStringsSep "\n" [
+ (pprLiteral ind "")
+ (pprItem ind x)
+ (pprLiteral ind "")
+ ];
+
+ pprAttrs = ind: x: libStr.concatStringsSep "\n" [
+ (pprLiteral ind "")
+ (pprAttr ind x)
+ (pprLiteral ind "")
+ ];
+
+ attrFilter = name: value: name != "_module" && value != null;
+
+ pprAttr = ind: x: libStr.concatStringsSep "\n" (lib.flatten (lib.mapAttrsToList (name: value: lib.optional (attrFilter name value) [
+ (pprKey "\t${ind}" name)
+ (pprExpr "\t${ind}" value)
+ ]) x));
+
}