summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorDaiderd Jordan <daiderd@gmail.com>2019-05-04 15:36:05 +0200
committerDaiderd Jordan <daiderd@gmail.com>2019-05-04 15:38:01 +0200
commitb85b9a4206a1d556d1d12babb35dc3887a6bdc58 (patch)
treec8ade5ab8c5050500f9667047750919ca12dcdd3 /doc
parent631fd857aa2bbceaa5376f84a837db5e4cf0990d (diff)
doc: add manual build for module options
Diffstat (limited to 'doc')
-rw-r--r--doc/manual/default.nix344
-rw-r--r--doc/manual/man-pages.xml42
-rw-r--r--doc/manual/manual.xml21
-rw-r--r--doc/manual/options-to-docbook.xsl229
-rw-r--r--doc/manual/overrides.css9
-rw-r--r--doc/manual/postprocess-option-descriptions.xsl115
-rw-r--r--doc/manual/style.css291
7 files changed, 1051 insertions, 0 deletions
diff --git a/doc/manual/default.nix b/doc/manual/default.nix
new file mode 100644
index 0000000..b5bdf6f
--- /dev/null
+++ b/doc/manual/default.nix
@@ -0,0 +1,344 @@
+{ pkgs, options, config, version, revision, extraSources ? [] }:
+
+with pkgs;
+
+let
+ lib = pkgs.lib;
+
+ # Remove invisible and internal options.
+ 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 x;
+
+ # Generate DocBook documentation for a list of packages. This is
+ # what `relatedPackages` option of `mkOption` from
+ # ../../../lib/options.nix influences.
+ #
+ # Each element of `relatedPackages` can be either
+ # - a string: that will be interpreted as an attribute name from `pkgs`,
+ # - a list: that will be interpreted as an attribute path from `pkgs`,
+ # - an attrset: that can specify `name`, `path`, `package`, `comment`
+ # (either of `name`, `path` is required, the rest are optional).
+ 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>"
+ # Lots of `longDescription's break DocBook, so we just wrap them into <programlisting>
+ + lib.optionalString (package.meta ? longDescription) "\n<programlisting>${package.meta.longDescription}</programlisting>"
+ + "</listitem>";
+ in "<itemizedlist>${lib.concatStringsSep "\n" (map (p: describe (unpack p)) packages)}</itemizedlist>";
+
+ optionsListDesc = lib.flip map optionsListVisible (opt: opt // {
+ # Clean up declaration sites to not refer to the NixOS source tree.
+ 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; });
+
+ # We need to strip references to /nix/store/* from options,
+ # including any `extraSources` if some modules came from elsewhere,
+ # or else the build will fail.
+ #
+ # E.g. if some `options` came from modules in ${pkgs.customModules}/nix,
+ # you'd need to include `extraSources = [ pkgs.customModules ]`
+ prefixesToStrip = map (p: "${toString p}/") ([ ../../.. ] ++ extraSources);
+ stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix) prefixesToStrip;
+
+ # Custom "less" that pushes up all the things ending in ".enable*"
+ # and ".package*"
+ 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;
+
+ # Customly sort option list for the man page.
+ optionsList = lib.sort optionLess optionsListDesc;
+
+ # Convert the list of options into an XML file.
+ optionsXML = builtins.toFile "options.xml" (builtins.toXML optionsList);
+
+ optionsDocBook = runCommand "options-db.xml" {} ''
+ optionsXML=${optionsXML}
+ if grep /darwin/modules $optionsXML; then
+ echo "The manual appears to depend on the location of Darwin, which is bad"
+ echo "since this prevents sharing via a channel. This is typically"
+ echo "caused by an option default that refers to a relative path (see above"
+ echo "for hints about the offending path)."
+ exit 1
+ fi
+ ${buildPackages.libxslt.bin}/bin/xsltproc \
+ --stringparam revision '${revision}' \
+ -o intermediate.xml ${./options-to-docbook.xsl} $optionsXML
+ ${buildPackages.libxslt.bin}/bin/xsltproc \
+ -o "$out" ${./postprocess-option-descriptions.xsl} intermediate.xml
+ '';
+
+ sources = lib.sourceFilesBySuffices ./. [".xml"];
+
+ modulesDoc = builtins.toFile "modules.xml" ''
+ <section xmlns:xi="http://www.w3.org/2001/XInclude" id="modules">
+ ${(lib.concatMapStrings (path: ''
+ <xi:include href="${path}" />
+ '') (lib.catAttrs "value" (config.meta.doc or [])))}
+ </section>
+ '';
+
+ generatedSources = runCommand "generated-docbook" {} ''
+ mkdir $out
+ ln -s ${modulesDoc} $out/modules.xml
+ ln -s ${optionsDocBook} $out/options-db.xml
+ printf "%s" "${version}" > $out/version
+ '';
+
+ copySources =
+ ''
+ cp -prd $sources/* . || true
+ ln -s ${generatedSources} ./generated
+ chmod -R u+w .
+ '';
+
+ toc = builtins.toFile "toc.xml"
+ ''
+ <toc role="chunk-toc">
+ <d:tocentry xmlns:d="http://docbook.org/ns/docbook" linkend="book-darwin-manual"><?dbhtml filename="index.html"?>
+ <d:tocentry linkend="ch-options"><?dbhtml filename="options.html"?></d:tocentry>
+ <d:tocentry linkend="ch-release-notes"><?dbhtml filename="release-notes.html"?></d:tocentry>
+ </d:tocentry>
+ </toc>
+ '';
+
+ manualXsltprocOptions = toString [
+ "--param section.autolabel 1"
+ "--param section.label.includes.component.label 1"
+ "--stringparam html.stylesheet 'style.css overrides.css highlightjs/mono-blue.css'"
+ "--stringparam html.script './highlightjs/highlight.pack.js ./highlightjs/loader.js'"
+ "--param xref.with.number.and.title 1"
+ "--param toc.section.depth 3"
+ "--stringparam admon.style ''"
+ "--stringparam callout.graphics.extension .svg"
+ "--stringparam current.docid manual"
+ "--param chunk.section.depth 0"
+ "--param chunk.first.sections 1"
+ "--param use.id.as.filename 1"
+ "--stringparam generate.toc 'book toc appendix toc'"
+ "--stringparam chunk.toc ${toc}"
+ ];
+
+ manual-combined = runCommand "darwin-manual-combined"
+ { inherit sources;
+ nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
+ meta.description = "The NixOS manual as plain docbook XML";
+ }
+ ''
+ ${copySources}
+
+ xmllint --xinclude --output ./manual-combined.xml ./manual.xml
+ xmllint --xinclude --noxincludenode \
+ --output ./man-pages-combined.xml ./man-pages.xml
+
+ # outputs the context of an xmllint error output
+ # LEN lines around the failing line are printed
+ function context {
+ # length of context
+ local LEN=6
+ # lines to print before error line
+ local BEFORE=4
+
+ # xmllint output lines are:
+ # file.xml:1234: there was an error on line 1234
+ while IFS=':' read -r file line rest; do
+ echo
+ if [[ -n "$rest" ]]; then
+ echo "$file:$line:$rest"
+ local FROM=$(($line>$BEFORE ? $line - $BEFORE : 1))
+ # number lines & filter context
+ nl --body-numbering=a "$file" | sed -n "$FROM,+$LEN p"
+ else
+ if [[ -n "$line" ]]; then
+ echo "$file:$line"
+ else
+ echo "$file"
+ fi
+ fi
+ done
+ }
+
+ function lintrng {
+ xmllint --debug --noout --nonet \
+ --relaxng ${docbook5}/xml/rng/docbook/docbook.rng \
+ "$1" \
+ 2>&1 | context 1>&2
+ # ^ redirect assumes xmllint doesn’t print to stdout
+ }
+
+ lintrng manual-combined.xml
+ lintrng man-pages-combined.xml
+
+ mkdir $out
+ cp manual-combined.xml $out/
+ cp man-pages-combined.xml $out/
+ '';
+
+ olinkDB = runCommand "manual-olinkdb"
+ { inherit sources;
+ nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
+ }
+ ''
+ xsltproc \
+ ${manualXsltprocOptions} \
+ --stringparam collect.xref.targets only \
+ --stringparam targets.filename "$out/manual.db" \
+ --nonet \
+ ${docbook_xsl_ns}/xml/xsl/docbook/xhtml/chunktoc.xsl \
+ ${manual-combined}/manual-combined.xml
+
+ cat > "$out/olinkdb.xml" <<EOF
+ <?xml version="1.0" encoding="utf-8"?>
+ <!DOCTYPE targetset SYSTEM
+ "file://${docbook_xsl_ns}/xml/xsl/docbook/common/targetdatabase.dtd" [
+ <!ENTITY manualtargets SYSTEM "file://$out/manual.db">
+ ]>
+ <targetset>
+ <targetsetinfo>
+ Allows for cross-referencing olinks between the manpages
+ and manual.
+ </targetsetinfo>
+
+ <document targetdoc="manual">&manualtargets;</document>
+ </targetset>
+ EOF
+ '';
+
+in rec {
+ inherit generatedSources;
+
+ # The NixOS options in JSON format.
+ optionsJSON = runCommand "options-json"
+ { meta.description = "List of NixOS options in JSON format";
+ }
+ ''
+ # Export list of options in different format.
+ dst=$out/share/doc/darwin
+ mkdir -p $dst
+
+ cp ${builtins.toFile "options.json" (builtins.unsafeDiscardStringContext (builtins.toJSON
+ (builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList))))
+ } $dst/options.json
+
+ mkdir -p $out/nix-support
+ echo "file json $dst/options.json" >> $out/nix-support/hydra-build-products
+ ''; # */
+
+ # Generate the NixOS manual.
+ manualHTML = runCommand "darwin-manual-html"
+ { inherit sources;
+ nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
+ meta.description = "The Darwin manual in HTML format";
+ allowedReferences = ["out"];
+ }
+ ''
+ # Generate the HTML manual.
+ dst=$out/share/doc/darwin
+ mkdir -p $dst
+ xsltproc \
+ ${manualXsltprocOptions} \
+ --stringparam target.database.document "${olinkDB}/olinkdb.xml" \
+ --stringparam id.warnings "1" \
+ --nonet --output $dst/ \
+ ${docbook_xsl_ns}/xml/xsl/docbook/xhtml/chunktoc.xsl \
+ ${manual-combined}/manual-combined.xml \
+ |& tee xsltproc.out
+ grep "^ID recommended on" xsltproc.out &>/dev/null && echo "error: some IDs are missing" && false
+ rm xsltproc.out
+
+ mkdir -p $dst/images/callouts
+ cp ${docbook_xsl_ns}/xml/xsl/docbook/images/callouts/*.svg $dst/images/callouts/
+
+ cp ${./style.css} $dst/style.css
+ cp ${./overrides.css} $dst/overrides.css
+ cp -r ${pkgs.documentation-highlighter} $dst/highlightjs
+
+ mkdir -p $out/nix-support
+ echo "nix-build out $out" >> $out/nix-support/hydra-build-products
+ echo "doc manual $dst" >> $out/nix-support/hydra-build-products
+ ''; # */
+
+ # Alias for backward compatibility. TODO(@oxij): remove eventually.
+ manual = manualHTML;
+
+ # Index page of the NixOS manual.
+ manualHTMLIndex = "${manualHTML}/share/doc/darwin/index.html";
+
+ manualEpub = runCommand "darwin-manual-epub"
+ { inherit sources;
+ buildInputs = [ libxml2.bin libxslt.bin zip ];
+ }
+ ''
+ # Generate the epub manual.
+ dst=$out/share/doc/darwin
+
+ xsltproc \
+ ${manualXsltprocOptions} \
+ --stringparam target.database.document "${olinkDB}/olinkdb.xml" \
+ --nonet --xinclude --output $dst/epub/ \
+ ${docbook_xsl_ns}/xml/xsl/docbook/epub/docbook.xsl \
+ ${manual-combined}/manual-combined.xml
+
+ mkdir -p $dst/epub/OEBPS/images/callouts
+ cp -r ${docbook_xsl_ns}/xml/xsl/docbook/images/callouts/*.svg $dst/epub/OEBPS/images/callouts # */
+ echo "application/epub+zip" > mimetype
+ manual="$dst/darwin-manual.epub"
+ zip -0Xq "$manual" mimetype
+ cd $dst/epub && zip -Xr9D "$manual" *
+
+ rm -rf $dst/epub
+
+ mkdir -p $out/nix-support
+ echo "doc-epub manual $manual" >> $out/nix-support/hydra-build-products
+ '';
+
+
+ # Generate the NixOS manpages.
+ manpages = runCommand "darwin-manpages"
+ { inherit sources;
+ nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
+ allowedReferences = ["out"];
+ }
+ ''
+ # Generate manpages.
+ mkdir -p $out/share/man
+ xsltproc --nonet \
+ --maxdepth 6000 \
+ --param man.output.in.separate.dir 1 \
+ --param man.output.base.dir "'$out/share/man/'" \
+ --param man.endnotes.are.numbered 0 \
+ --param man.break.after.slash 1 \
+ --stringparam target.database.document "${olinkDB}/olinkdb.xml" \
+ ${docbook_xsl_ns}/xml/xsl/docbook/manpages/docbook.xsl \
+ ${manual-combined}/man-pages-combined.xml
+ '';
+
+}
+
diff --git a/doc/manual/man-pages.xml b/doc/manual/man-pages.xml
new file mode 100644
index 0000000..2490f63
--- /dev/null
+++ b/doc/manual/man-pages.xml
@@ -0,0 +1,42 @@
+<reference xmlns="http://docbook.org/ns/docbook"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <title>Darwin Reference Pages</title>
+ <info>
+ <author><personname><firstname>Daiderd</firstname><surname>Jordan</surname></personname>
+ <contrib>Author</contrib>
+ </author>
+ <copyright><year>2016-2019</year><holder>Daiderd Jordan</holder>
+ </copyright>
+ </info>
+
+ <refentry>
+ <refmeta>
+ <refentrytitle><filename>configuration.nix</filename>
+ </refentrytitle><manvolnum>5</manvolnum>
+ <refmiscinfo class="source">Darwin</refmiscinfo>
+ <!-- <refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo> -->
+ </refmeta>
+ <refnamediv>
+ <refname><filename>configuration.nix</filename>
+ </refname><refpurpose>Darwin system configuration specification</refpurpose>
+ </refnamediv>
+ <refsection>
+ <title>Description</title>
+ <para>
+ The file <filename>configuration.nix</filename> contains the
+ declarative specification of your Darwin system configuration. The command
+ <command>darwin-rebuild</command> takes this file and realises the system
+ configuration specified therein.
+ </para>
+ </refsection>
+ <refsection>
+ <title>Options</title>
+ <para>
+ You can use the following options in <filename>configuration.nix</filename>.
+ </para>
+ <xi:include href="./generated/options-db.xml"
+ xpointer="configuration-variable-list" />
+ </refsection>
+ </refentry>
+</reference>
diff --git a/doc/manual/manual.xml b/doc/manual/manual.xml
new file mode 100644
index 0000000..a334342
--- /dev/null
+++ b/doc/manual/manual.xml
@@ -0,0 +1,21 @@
+<book xmlns="http://docbook.org/ns/docbook"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ version="5.0"
+ xml:id="book-darwin-manual">
+ <info>
+ <title>Darwin Manual</title>
+ <subtitle>Version <xi:include href="./generated/version" parse="text" />
+ </subtitle>
+ </info>
+ <preface xml:id="preface">
+ <title>Preface</title>
+ <para>Nix modules for darwin.</para>
+ </preface>
+ <chapter xml:id="sec-options">
+ <title>Configuration Options</title>
+ <xi:include href="./generated/options-db.xml"
+ xpointer="configuration-variable-list" />
+ </chapter>
+</book>
+
diff --git a/doc/manual/options-to-docbook.xsl b/doc/manual/options-to-docbook.xsl
new file mode 100644
index 0000000..09f5e08
--- /dev/null
+++ b/doc/manual/options-to-docbook.xsl
@@ -0,0 +1,229 @@
+<?xml version="1.0"?>
+
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:str="http://exslt.org/strings"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:nixos="tag:nixos.org"
+ xmlns="http://docbook.org/ns/docbook"
+ extension-element-prefixes="str"
+ >
+
+ <xsl:output method='xml' encoding="UTF-8" />
+
+ <xsl:param name="revision" />
+ <xsl:param name="program" />
+
+ <xsl:template match="/expr/list">
+ <appendix xml:id="appendix-configuration-options">
+ <title>Configuration Options</title>
+ <variablelist xml:id="configuration-variable-list">
+ <xsl:for-each select="attrs">
+ <xsl:variable name="id" select="concat('opt-', str:replace(str:replace(str:replace(str:replace(attr[@name = 'name']/string/@value, '*', '_'), '&lt;', '_'), '>', '_'), '?', '_'))" />
+ <varlistentry>
+ <term xlink:href="#{$id}">
+ <xsl:attribute name="xml:id"><xsl:value-of select="$id"/></xsl:attribute>
+ <option>
+ <xsl:value-of select="attr[@name = 'name']/string/@value" />
+ </option>
+ </term>
+
+ <listitem>
+
+ <nixos:option-description>
+ <para>
+ <xsl:value-of disable-output-escaping="yes"
+ select="attr[@name = 'description']/string/@value" />
+ </para>
+ </nixos:option-description>
+
+ <xsl:if test="attr[@name = 'type']">
+ <para>
+ <emphasis>Type:</emphasis>
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="attr[@name = 'type']/string/@value"/>
+ <xsl:if test="attr[@name = 'readOnly']/bool/@value = 'true'">
+ <xsl:text> </xsl:text>
+ <emphasis>(read only)</emphasis>
+ </xsl:if>
+ </para>
+ </xsl:if>
+
+ <xsl:if test="attr[@name = 'default']">
+ <para>
+ <emphasis>Default:</emphasis>
+ <xsl:text> </xsl:text>
+ <xsl:apply-templates select="attr[@name = 'default']" mode="top" />
+ </para>
+ </xsl:if>
+
+ <xsl:if test="attr[@name = 'example']">
+ <para>
+ <emphasis>Example:</emphasis>
+ <xsl:text> </xsl:text>
+ <xsl:choose>
+ <xsl:when test="attr[@name = 'example']/attrs[attr[@name = '_type' and string[@value = 'literalExample']]]">
+ <programlisting><xsl:value-of select="attr[@name = 'example']/attrs/attr[@name = 'text']/string/@value" /></programlisting>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="attr[@name = 'example']" mode="top" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </para>
+ </xsl:if>
+
+ <xsl:if test="attr[@name = 'relatedPackages']">
+ <para>
+ <emphasis>Related packages:</emphasis>
+ <xsl:text> </xsl:text>
+ <xsl:value-of disable-output-escaping="yes"
+ select="attr[@name = 'relatedPackages']/string/@value" />
+ </para>
+ </xsl:if>
+
+ <xsl:if test="count(attr[@name = 'declarations']/list/*) != 0">
+ <para>
+ <emphasis>Declared by:</emphasis>
+ </para>
+ <xsl:apply-templates select="attr[@name = 'declarations']" />
+ </xsl:if>
+
+ <xsl:if test="count(attr[@name = 'definitions']/list/*) != 0">
+ <para>
+ <emphasis>Defined by:</emphasis>
+ </para>
+ <xsl:apply-templates select="attr[@name = 'definitions']" />
+ </xsl:if>
+
+ </listitem>
+
+ </varlistentry>
+
+ </xsl:for-each>
+
+ </variablelist>
+ </appendix>
+ </xsl:template>
+
+
+ <xsl:template match="*" mode="top">
+ <xsl:choose>
+ <xsl:when test="string[contains(@value, '&#010;')]">
+<programlisting>
+<xsl:text>''
+</xsl:text><xsl:value-of select='str:replace(string/@value, "${", "&apos;&apos;${")' /><xsl:text>''</xsl:text></programlisting>
+ </xsl:when>
+ <xsl:otherwise>
+ <literal><xsl:apply-templates /></literal>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+
+ <xsl:template match="null">
+ <xsl:text>null</xsl:text>
+ </xsl:template>
+
+
+ <xsl:template match="string">
+ <xsl:choose>
+ <xsl:when test="(contains(@value, '&quot;') or contains(@value, '\')) and not(contains(@value, '&#010;'))">
+ <xsl:text>''</xsl:text><xsl:value-of select='str:replace(@value, "${", "&apos;&apos;${")' /><xsl:text>''</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>"</xsl:text><xsl:value-of select="str:replace(str:replace(str:replace(str:replace(@value, '\', '\\'), '&quot;', '\&quot;'), '&#010;', '\n'), '$', '\$')" /><xsl:text>"</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+
+ <xsl:template match="int">
+ <xsl:value-of select="@value" />
+ </xsl:template>
+
+
+ <xsl:template match="bool[@value = 'true']">
+ <xsl:text>true</xsl:text>
+ </xsl:template>
+
+
+ <xsl:template match="bool[@value = 'false']">
+ <xsl:text>false</xsl:text>
+ </xsl:template>
+
+
+ <xsl:template match="list">
+ [
+ <xsl:for-each select="*">
+ <xsl:apply-templates select="." />
+ <xsl:text> </xsl:text>
+ </xsl:for-each>
+ ]
+ </xsl:template>
+
+
+ <xsl:template match="attrs[attr[@name = '_type' and string[@value = 'literalExample']]]">
+ <xsl:value-of select="attr[@name = 'text']/string/@value" />
+ </xsl:template>
+
+
+ <xsl:template match="attrs">
+ {
+ <xsl:for-each select="attr">
+ <xsl:value-of select="@name" />
+ <xsl:text> = </xsl:text>
+ <xsl:apply-templates select="*" /><xsl:text>; </xsl:text>
+ </xsl:for-each>
+ }
+ </xsl:template>
+
+
+ <xsl:template match="derivation">
+ <replaceable>(build of <xsl:value-of select="attr[@name = 'name']/string/@value" />)</replaceable>
+ </xsl:template>
+
+ <xsl:template match="attr[@name = 'declarations' or @name = 'definitions']">
+ <simplelist>
+ <xsl:for-each select="list/string">
+ <member><filename>
+ <!-- Hyperlink the filename either to the NixOS Subversion
+ repository (if it’s a module and we have a revision number),
+ or to the local filesystem. -->
+ <xsl:choose>
+ <xsl:when test="not(starts-with(@value, '/'))">
+ <xsl:choose>
+ <xsl:when test="$revision = 'local'">
+ <xsl:attribute name="xlink:href">https://github.com/LnL7/nix-darwin/blob/master/<xsl:value-of select="@value"/></xsl:attribute>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:attribute name="xlink:href">https://github.com/LnL7/nix-darwin/blob/<xsl:value-of select="$revision"/>/<xsl:value-of select="@value"/></xsl:attribute>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:attribute name="xlink:href">file://<xsl:value-of select="@value"/></xsl:attribute>
+ </xsl:otherwise>
+ </xsl:choose>
+ <!-- Print the filename and make it user-friendly by replacing the
+ /nix/store/<hash> prefix by the default location of darwin
+ sources. -->
+ <xsl:choose>
+ <xsl:when test="not(starts-with(@value, '/'))">
+ &lt;<xsl:value-of select="@value"/>&gt;
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@value" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </filename></member>
+ </xsl:for-each>
+ </simplelist>
+ </xsl:template>
+
+
+ <xsl:template match="function">
+ <xsl:text>λ</xsl:text>
+ </xsl:template>
+
+
+</xsl:stylesheet>
diff --git a/doc/manual/overrides.css b/doc/manual/overrides.css
new file mode 100644
index 0000000..4c7d4a3
--- /dev/null
+++ b/doc/manual/overrides.css
@@ -0,0 +1,9 @@
+.docbook .xref img[src^=images\/callouts\/],
+.screen img,
+.programlisting img {
+ width: 1em;
+}
+
+.calloutlist img {
+ width: 1.5em;
+}
diff --git a/doc/manual/postprocess-option-descriptions.xsl b/doc/manual/postprocess-option-descriptions.xsl
new file mode 100644
index 0000000..1201c76
--- /dev/null
+++ b/doc/manual/postprocess-option-descriptions.xsl
@@ -0,0 +1,115 @@
+<?xml version="1.0"?>
+
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:str="http://exslt.org/strings"
+ xmlns:exsl="http://exslt.org/common"
+ xmlns:db="http://docbook.org/ns/docbook"
+ xmlns:nixos="tag:nixos.org"
+ extension-element-prefixes="str exsl">
+ <xsl:output method='xml' encoding="UTF-8" />
+
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template name="break-up-description">
+ <xsl:param name="input" />
+ <xsl:param name="buffer" />
+
+ <!-- Every time we have two newlines following each other, we want to
+ break it into </para><para>. -->
+ <xsl:variable name="parbreak" select="'&#xa;&#xa;'" />
+
+ <!-- Similar to "(head:tail) = input" in Haskell. -->
+ <xsl:variable name="head" select="$input[1]" />
+ <xsl:variable name="tail" select="$input[position() &gt; 1]" />
+
+ <xsl:choose>
+ <xsl:when test="$head/self::text() and contains($head, $parbreak)">
+ <!-- If the haystack provided to str:split() directly starts or
+ ends with $parbreak, it doesn't generate a <token/> for that,
+ so we are doing this here. -->
+ <xsl:variable name="splitted-raw">
+ <xsl:if test="starts-with($head, $parbreak)"><token /></xsl:if>
+ <xsl:for-each select="str:split($head, $parbreak)">
+ <token><xsl:value-of select="node()" /></token>
+ </xsl:for-each>
+ <!-- Something like ends-with($head, $parbreak), but there is
+ no ends-with() in XSLT, so we need to use substring(). -->
+ <xsl:if test="
+ substring($head, string-length($head) -
+ string-length($parbreak) + 1) = $parbreak
+ "><token /></xsl:if>
+ </xsl:variable>
+ <xsl:variable name="splitted"
+ select="exsl:node-set($splitted-raw)/token" />
+ <!-- The buffer we had so far didn't contain any text nodes that
+ contain a $parbreak, so we can put the buffer along with the
+ first token of $splitted into a para element. -->
+ <para xmlns="http://docbook.org/ns/docbook">
+ <xsl:apply-templates select="exsl:node-set($buffer)" />
+ <xsl:apply-templates select="$splitted[1]/node()" />
+ </para>
+ <!-- We have already emitted the first splitted result, so the
+ last result is going to be set as the new $buffer later
+ because its contents may not be directly followed up by a
+ $parbreak. -->
+ <xsl:for-each select="$splitted[position() &gt; 1
+ and position() &lt; last()]">
+ <para xmlns="http://docbook.org/ns/docbook">
+ <xsl:apply-templates select="node()" />
+ </para>
+ </xsl:for-each>
+ <xsl:call-template name="break-up-description">
+ <xsl:with-param name="input" select="$tail" />
+ <xsl:with-param name="buffer" select="$splitted[last()]/node()" />
+ </xsl:call-template>
+ </xsl:when>
+ <!-- Either non-text node or one without $parbreak, which we just
+ want to buffer and continue recursing. -->
+ <xsl:when test="$input">
+ <xsl:call-template name="break-up-description">
+ <xsl:with-param name="input" select="$tail" />
+ <!-- This essentially appends $head to $buffer. -->
+ <xsl:with-param name="buffer">
+ <xsl:if test="$buffer">
+ <xsl:for-each select="exsl:node-set($buffer)">
+ <xsl:apply-templates select="." />
+ </xsl:for-each>
+ </xsl:if>
+ <xsl:apply-templates select="$head" />
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+ <!-- No more $input, just put the remaining $buffer in a para. -->
+ <xsl:otherwise>
+ <para xmlns="http://docbook.org/ns/docbook">
+ <xsl:apply-templates select="exsl:node-set($buffer)" />
+ </para>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="nixos:option-description">
+ <xsl:choose>
+ <!--
+ Only process nodes that are comprised of a single <para/> element,
+ because if that's not the case the description already contains
+ </para><para> in between and we need no further processing.
+ -->
+ <xsl:when test="count(db:para) > 1">
+ <xsl:apply-templates select="node()" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="break-up-description">
+ <xsl:with-param name="input"
+ select="exsl:node-set(db:para/node())" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/doc/manual/style.css b/doc/manual/style.css
new file mode 100644
index 0000000..474dd32
--- /dev/null
+++ b/doc/manual/style.css
@@ -0,0 +1,291 @@
+/* Copied from http://bakefile.sourceforge.net/, which appears
+ licensed under the GNU GPL. */
+
+
+/***************************************************************************
+ Basic headers and text:
+ ***************************************************************************/
+
+body
+{
+ font-family: "Nimbus Sans L", sans-serif;
+ font-size: 1em;
+ background: white;
+ margin: 2em 1em 2em 1em;
+}
+
+h1, h2, h3, h4
+{
+ color: #005aa0;
+}
+
+h1 /* title */
+{
+ font-size: 200%;
+}
+
+h2 /* chapters, appendices, subtitle */
+{
+ font-size: 180%;
+}
+
+div.book
+{
+ text-align: center;
+}
+
+div.book > div
+{
+ /*
+ * based on https://medium.com/@zkareemz/golden-ratio-62b3b6d4282a
+ * we do 70 characters per line to fit code listings better
+ * 70 * (font-size / 1.618)
+ * expression for emacs:
+ * (* 70 (/ 1 1.618))
+ */
+ max-width: 43.2em;
+ text-align: left;
+ margin: auto;
+}
+
+/* Extra space between chapters, appendices. */
+div.chapter > div.titlepage h2, div.appendix > div.titlepage h2
+{
+ margin-top: 1.5em;
+}
+
+div.section > div.titlepage h2 /* sections */
+{
+ font-size: 150%;
+ margin-top: 1.5em;
+}
+
+h3 /* subsections */
+{
+ font-size: 125%;
+}
+
+div.simplesect h2
+{
+ font-size: 110%;
+}
+
+div.appendix h3
+{
+ font-size: 150%;
+ margin-top: 1.5em;
+}
+
+div.refnamediv h2, div.refsynopsisdiv h2, div.refsection h2 /* refentry parts */
+{
+ margin-top: 1.4em;
+ font-size: 125%;
+}
+
+div.refsection h3
+{
+ font-size: 110%;
+}
+
+
+/***************************************************************************
+ Examples:
+ ***************************************************************************/
+
+div.example
+{
+ border: 1px solid #b0b0b0;
+ padding: 6px 6px;
+ margin-left: 1.5em;
+ margin-right: 1.5em;
+ background: #f4f4f8;
+ border-radius: 0.4em;
+ box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
+}
+
+div.example p.title
+{
+ margin-top: 0em;
+}
+
+div.example pre
+{
+ box-shadow: none;
+}
+
+
+/***************************************************************************
+ Screen dumps:
+ ***************************************************************************/
+
+pre.screen, pre.programlisting
+{
+ border: 1px solid #b0b0b0;
+ padding: 3px 3px;
+ margin-left: 0.5em;
+ margin-right: 0.5em;
+
+ background: #f4f4f8;
+ font-family: monospace;
+ border-radius: 0.4em;
+ box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
+}
+
+div.example pre.programlisting
+{
+ border: 0px;
+ padding: 0 0;
+ margin: 0 0 0 0;
+}
+
+/***************************************************************************
+ Notes, warnings etc:
+ ***************************************************************************/
+
+.note, .warning
+{
+ border: 1px solid #b0b0b0;
+ padding: 3px 3px;
+ margin-left: 1.5em;
+ margin-right: 1.5em;
+ margin-bottom: 1em;
+ padding: 0.3em 0.3em 0.3em 0.3em;
+ background: #fffff5;
+ border-radius: 0.4em;
+ box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
+}
+
+div.note, div.warning
+{
+ font-style: italic;
+}
+
+div.note h3, div.warning h3
+{
+ color: red;
+ font-size: 100%;
+ padding-right: 0.5em;
+ display: inline;
+}
+
+div.note p, div.warning p
+{
+ margin-bottom: 0em;
+}
+
+div.note h3 + p, div.warning h3 + p
+{
+ display: inline;
+}
+
+div.note h3
+{
+ color: blue;
+ font-size: 100%;
+}
+
+div.navfooter *
+{
+ font-size: 90%;
+}
+
+
+/***************************************************************************
+ Links colors and highlighting:
+ ***************************************************************************/
+
+a { text-decoration: none; }
+a:hover { text-decoration: underline; }
+a:link { color: #0048b3; }
+a:visited { color: #002a6a; }
+
+
+/***************************************************************************
+ Table of contents:
+ ***************************************************************************/
+
+div.toc
+{
+ font-size: 90%;
+}
+
+div.toc dl
+{
+ margin-top: 0em;
+ margin-bottom: 0em;
+}
+
+
+/***************************************************************************
+ Special elements:
+ ***************************************************************************/
+
+tt, code
+{
+ color: #400000;
+}
+
+.term
+{
+ font-weight: bold;
+
+}
+
+div.variablelist dd p, div.glosslist dd p
+{
+ margin-top: 0em;
+}
+
+div.variablelist dd, div.glosslist dd
+{
+ margin-left: 1.5em;
+}
+
+div.glosslist dt
+{
+ font-style: italic;
+}
+
+.varname
+{
+ color: #400000;
+}
+
+span.command strong
+{
+ font-weight: normal;
+ color: #400000;
+}
+
+div.calloutlist table
+{
+ box-shadow: none;
+}
+
+table
+{
+ border-collapse: collapse;
+ box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
+}
+
+table.simplelist
+{
+ text-align: left;
+ color: #005aa0;
+ border: 0;
+ padding: 5px;
+ background: #fffff5;
+ font-weight: normal;
+ font-style: italic;
+ box-shadow: none;
+ margin-bottom: 1em;
+}
+
+div.navheader table, div.navfooter table {
+ box-shadow: none;
+}
+
+div.affiliation
+{
+ font-style: italic;
+}