Skip to content

Instantly share code, notes, and snippets.

@sphaugh
Created January 10, 2019 18:45
Show Gist options
  • Save sphaugh/a32e58c97c6cc4faaef7e6a1674864ac to your computer and use it in GitHub Desktop.
Save sphaugh/a32e58c97c6cc4faaef7e6a1674864ac to your computer and use it in GitHub Desktop.

Revisions

  1. sphaugh created this gist Jan 10, 2019.
    91 changes: 91 additions & 0 deletions gen-docs.nix
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,91 @@
    with import ./. {};

    let

    extraSources = [];
    lib = pkgs.lib;

    optionsListVisible =
    lib.filter (opt: opt.visible && !opt.internal)
    (lib.optionAttrSetToDocList options);

    # Replace functions by the string <function>
    substFunction = x:
    if builtins.isAttrs x then lib.mapAttrs (name: substFunction) x
    else if builtins.isList x then map substFunction x
    else if lib.isFunction x then "<function>"
    else if isPath x then toString x
    else x;

    isPath = x: (builtins.typeOf x) == "path";

    optionsListDesc = lib.flip map optionsListVisible (opt: opt // {
    description = let attempt = builtins.tryEval opt.description; in
    if attempt.success then attempt.value else "N/A";
    declarations = map stripAnyPrefixes opt.declarations;
    }
    // lib.optionalAttrs (opt ? example) {
    example = substFunction opt.example; }
    // lib.optionalAttrs (opt ? default) {
    default = substFunction opt.default; }
    // lib.optionalAttrs (opt ? type) {
    type = substFunction opt.type; }
    // lib.optionalAttrs
    (opt ? relatedPackages && opt.relatedPackages != []) {
    relatedPackages = genRelatedPackages opt.relatedPackages; }
    );

    genRelatedPackages = packages: let
    unpack = p: if lib.isString p then { name = p; }
    else if lib.isList p then { path = p; }
    else p;
    describe = args: let
    title = args.title or null;
    name = args.name or (lib.concatStringsSep "." args.path);
    path = args.path or [ args.name ];
    package = args.package or (lib.attrByPath path (throw
    "Invalid package attribute path '${toString path}'") pkgs);
    in "<listitem>"
    + "<para><literal>${lib.optionalString (title != null)
    "${title} aka "}pkgs.${name} (${package.meta.name})</literal>"
    + lib.optionalString (!package.meta.available)
    " <emphasis>[UNAVAILABLE]</emphasis>"
    + ": ${package.meta.description or "???"}.</para>"
    + lib.optionalString (args ? comment)
    "\n<para>${args.comment}</para>"
    + lib.optionalString (package.meta ? longDescription)
    "\n<programlisting>${package.meta.longDescription}"
    + "</programlisting>"
    + "</listitem>";
    in "<itemizedlist>${lib.concatStringsSep "\n" (map (p:
    describe (unpack p)) packages)}</itemizedlist>";

    optionLess = a: b:
    let
    ise = lib.hasPrefix "enable";
    isp = lib.hasPrefix "package";
    cmp = lib.splitByAndCompare ise lib.compare
    (lib.splitByAndCompare isp lib.compare lib.compare);
    in lib.compareLists cmp a.loc b.loc < 0;


    prefixesToStrip = map (p: "${toString p}/") ([ ../../.. ] ++ extraSources);
    stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix) prefixesToStrip;

    ###############################################################################

    # This is the REAL meat of what we were after.
    # Output this however you want.
    optionsList = lib.sort optionLess optionsListDesc;

    optionsJSON = builtins.unsafeDiscardStringContext (builtins.toJSON
    (builtins.listToAttrs (map (o: {
    name = o.name;
    value = removeAttrs o [
    # Select the fields you want to drop here:
    "name" "visible" "internal" "loc" "readOnly" ];
    }) optionsList)));

    in

    pkgs.writeText "options.json" optionsJSON