{ 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)); }