{ depot, lib, pkgs, ... }: let inherit (depot.nix) getBins runExecline yants ; inherit (depot.tools) cheddar ; inherit (pkgs) mandoc coreutils fetchurl writers ; bins = getBins cheddar [ "cheddar" ] // getBins mandoc [ "mandoc" ] // getBins coreutils [ "cat" "mv" "mkdir" ] ; normalizeDrv = fetchurl { url = "https://necolas.github.io/normalize.css/8.0.1/normalize.css"; sha256 = "04jmvybwh2ks4dlnfa70sb3a3z3ig4cv0ya9rizjvm140xq1h22q"; }; execlineStdoutInto = target: line: [ "redirfd" "-w" "1" target ] ++ line; # I will not write a pure nix markdown renderer # I will not write a pure nix markdown renderer # I will not write a pure nix markdown renderer # I will not write a pure nix markdown renderer # I will not write a pure nix markdown renderer markdown = md: let html = runExecline.local "rendered-markdown" { stdin = md; } ([ "importas" "-iu" "out" "out" ] ++ execlineStdoutInto "$out" [ bins.cheddar "--about-filter" "description.md" ]); in builtins.readFile html; indexTemplate = { title, description, pages ? [ ] }: '' <!doctype html> <html> <head> <meta charset="utf-8"> <title>${title}</title> <link rel="stylesheet" type="text/css" href="style.css"/> </head> <body> <div class="index-text"> <h1>${title}</h1> ${markdown description} <h2>man pages</h2> <ul> ${lib.concatMapStrings ({ name, section, ... }: '' <li><a href="${name}.${toString section}.html">${name}(${toString section})</a></li> '') pages} </ul> </div> </body> </html> ''; defaultStyle = import ./defaultStyle.nix { }; # This deploy script automatically copies the build result into # a TARGET directory and marks it as writeable optionally. # It is exposed as the deploy attribute of the result of # htmlman, so an htmlman expression can be used like this: # nix-build -A deploy htmlman.nix && ./result target_dir deployScript = title: drv: writers.writeDash "deploy-${title}" '' usage() { printf 'Usage: %s [-w] TARGET\n\n' "$0" printf 'Deploy htmlman documentation to TARGET directory.\n\n' printf ' -h Display this help message\n' printf ' -w Make TARGET directory writeable\n' } if test "$#" -lt 1; then usage exit 100 fi writeable=false while test "$#" -gt 0; do case "$1" in -h) usage exit 0 ;; -w) writeable=true ;; -*) usage exit 100 ;; *) if test -z "$target"; then target="$1" else echo "Too many arguments" exit 100 fi ;; esac shift done if test -z "$target"; then echo "Missing TARGET" usage exit 100 fi set -ex mkdir -p "$target" cp -RTL --reflink=auto "${drv}" "$target" if $writeable; then chmod -R +w "$target" fi ''; htmlman = { title # title of the index page , description ? "" # description which is displayed after # the main heading on the index page , pages ? [ ] # man pages of the following structure: # { # name : string; # section : int; # path : either path string; # } # path is optional, if it is not given, # the man page source must be located at # "${manDir}/${name}.${toString section}" , manDir ? null # directory in which man page sources are located , style ? defaultStyle # CSS to use as a string , normalizeCss ? true # whether to include normalize.css before the custom CSS , linkXr ? "all" # How to handle cross references in the html output: # # * none: don't convert cross references into hyperlinks # * all: link all cross references as if they were # rendered into $out by htmlman # * inManDir: link to all man pages which have their source # in `manDir` and use the format string defined # in linkXrFallback for all other cross references. , linkXrFallback ? "https://manpages.debian.org/unstable/%N.%S.en.html" # fallback link to use if linkXr == "inManDir" and the man # page is not in ${manDir}. Placeholders %N (name of page) # and %S (section of page) can be used. See mandoc(1) for # more information. }: let linkXrEnum = yants.enum "linkXr" [ "all" "inManDir" "none" ]; index = indexTemplate { inherit title description pages; }; resolvePath = { path ? null, name, section }: if path != null then path else "${manDir}/${name}.${toString section}"; mandocOpts = lib.concatStringsSep "," ([ "style=style.css" ] ++ linkXrEnum.match linkXr { all = [ "man=./%N.%S.html" ]; inManDir = [ "man=./%N.%S.html;${linkXrFallback}" ]; none = [ ]; }); html = runExecline.local "htmlman-${title}" { derivationArgs = { inherit index style; passAsFile = [ "index" "style" ]; }; } ([ "multisubstitute" [ "importas" "-iu" "out" "out" "importas" "-iu" "index" "indexPath" "importas" "-iu" "style" "stylePath" ] "if" [ bins.mkdir "-p" "$out" ] "if" [ bins.mv "$index" "\${out}/index.html" ] "if" (execlineStdoutInto "\${out}/style.css" [ "if" ([ bins.cat ] ++ lib.optional normalizeCss normalizeDrv ++ [ "$style" ]) ]) # let mandoc check for available man pages "execline-cd" "${manDir}" ] ++ lib.concatMap ({ name, section, ... }@p: execlineStdoutInto "\${out}/${name}.${toString section}.html" [ "if" [ bins.mandoc "-mdoc" "-T" "html" "-O" mandocOpts (resolvePath p) ] ]) pages); in html // { deploy = deployScript title html; }; in htmlman