diff options
author | pennae <github@quasiparticle.net> | 2023-02-19 23:03:32 +0100 |
---|---|---|
committer | pennae <github@quasiparticle.net> | 2023-02-21 18:26:41 +0100 |
commit | d520d55dee017fff8b3d0682260e12a27035378e (patch) | |
tree | 89115fea8977daf1b56183c63fbd934991cc1f46 /pkgs/tools/nix/nixos-render-docs/src | |
parent | 82e62614e9171981a3972940b8e96e02c7e55f83 (diff) |
nixos-render-docs: add options html renderer
it's not hooked up to anything yet, but that will come soon. there's a bit of docbook compat here that must be interoperable with the actual docbook exporter, but luckily it's not all that much.
Diffstat (limited to 'pkgs/tools/nix/nixos-render-docs/src')
-rw-r--r-- | pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/options.py | 116 |
1 files changed, 111 insertions, 5 deletions
diff --git a/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/options.py b/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/options.py index 88c6d74433189..06e5f97112168 100644 --- a/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/options.py +++ b/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/options.py @@ -1,14 +1,15 @@ from __future__ import annotations import argparse +import html import json +import xml.sax.saxutils as xml from abc import abstractmethod from collections.abc import Mapping, Sequence from markdown_it.token import Token from typing import Any, Generic, Optional from urllib.parse import quote -from xml.sax.saxutils import escape, quoteattr import markdown_it @@ -17,7 +18,9 @@ from . import parallel from .asciidoc import AsciiDocRenderer, asciidoc_escape from .commonmark import CommonMarkRenderer from .docbook import DocBookRenderer, make_xml_id +from .html import HTMLRenderer from .manpage import ManpageRenderer, man_escape +from .manual_structure import XrefTarget from .md import Converter, md_escape, md_make_code from .types import OptionLoc, Option, RenderedOption @@ -240,10 +243,10 @@ class DocBookConverter(BaseConverter[OptionsDocBookRenderer]): def _decl_def_entry(self, href: Optional[str], name: str) -> list[str]: if href is not None: - href = " xlink:href=" + quoteattr(href) + href = " xlink:href=" + xml.quoteattr(href) return [ f"<member><filename{href}>", - escape(name), + xml.escape(name), "</filename></member>" ] @@ -273,8 +276,8 @@ class DocBookConverter(BaseConverter[OptionsDocBookRenderer]): result += [ "<varlistentry>", # NOTE adding extra spaces here introduces spaces into xref link expansions - (f"<term xlink:href={quoteattr('#' + id)} xml:id={quoteattr(id)}>" + - f"<option>{escape(name)}</option></term>"), + (f"<term xlink:href={xml.quoteattr('#' + id)} xml:id={xml.quoteattr(id)}>" + + f"<option>{xml.escape(name)}</option></term>"), "<listitem>" ] result += opt.lines @@ -524,6 +527,109 @@ class AsciiDocConverter(BaseConverter[OptionsAsciiDocRenderer]): return "\n".join(result) +class OptionsHTMLRenderer(OptionDocsRestrictions, HTMLRenderer): + # TODO docbook compat. must be removed together with the matching docbook handlers. + def ordered_list_open(self, token: Token, tokens: Sequence[Token], i: int) -> str: + token.meta['compact'] = False + return super().ordered_list_open(token, tokens, i) + def bullet_list_open(self, token: Token, tokens: Sequence[Token], i: int) -> str: + token.meta['compact'] = False + return super().bullet_list_open(token, tokens, i) + def fence(self, token: Token, tokens: Sequence[Token], i: int) -> str: + # TODO use token.info. docbook doesn't so we can't yet. + return f'<pre class="programlisting">{html.escape(token.content)}</pre>' + +class HTMLConverter(BaseConverter[OptionsHTMLRenderer]): + __option_block_separator__ = "" + + def __init__(self, manpage_urls: Mapping[str, str], revision: str, markdown_by_default: bool, + varlist_id: str, id_prefix: str, xref_targets: Mapping[str, XrefTarget]): + super().__init__(revision, markdown_by_default) + self._xref_targets = xref_targets + self._varlist_id = varlist_id + self._id_prefix = id_prefix + self._renderer = OptionsHTMLRenderer(manpage_urls, self._xref_targets) + + def _parallel_render_prepare(self) -> Any: + return (self._renderer._manpage_urls, self._revision, self._markdown_by_default, + self._varlist_id, self._id_prefix, self._xref_targets) + @classmethod + def _parallel_render_init_worker(cls, a: Any) -> HTMLConverter: + return cls(*a) + + def _render_code(self, option: dict[str, Any], key: str) -> list[str]: + if lit := option_is(option, key, 'literalDocBook'): + raise RuntimeError("can't render html in the presence of docbook") + else: + return super()._render_code(option, key) + + def _render_description(self, desc: str | dict[str, Any]) -> list[str]: + if isinstance(desc, str) and not self._markdown_by_default: + raise RuntimeError("can't render html in the presence of docbook") + else: + return super()._render_description(desc) + + def _related_packages_header(self) -> list[str]: + return [ + '<p><span class="emphasis"><em>Related packages:</em></span></p>', + ] + + def _decl_def_header(self, header: str) -> list[str]: + return [ + f'<p><span class="emphasis"><em>{header}:</em></span></p>', + '<table border="0" summary="Simple list" class="simplelist">' + ] + + def _decl_def_entry(self, href: Optional[str], name: str) -> list[str]: + if href is not None: + href = f' href="{html.escape(href, True)}"' + return [ + "<tr><td>", + f'<code class="filename"><a class="filename" {href} target="_top">', + f'{html.escape(name)}', + '</a></code>', + "</td></tr>" + ] + + def _decl_def_footer(self) -> list[str]: + return [ "</table>" ] + + def finalize(self) -> str: + result = [] + + result += [ + '<div class="variablelist">', + f'<a id="{html.escape(self._varlist_id, True)}"></a>', + ' <dl class="variablelist">', + ] + + for (name, opt) in self._sorted_options(): + id = make_xml_id(self._id_prefix + name) + target = self._xref_targets[id] + result += [ + '<dt>', + ' <span class="term">', + # docbook compat, these could be one tag + f' <a id="{html.escape(id, True)}"></a><a class="term" href="{target.href()}">' + # no spaces here (and string merging) for docbook output compat + f'<code class="option">{html.escape(name)}</code>', + ' </a>', + ' </span>', + '</dt>', + '<dd>', + ] + result += opt.lines + result += [ + "</dd>", + ] + + result += [ + " </dl>", + "</div>" + ] + + return "\n".join(result) + def _build_cli_db(p: argparse.ArgumentParser) -> None: p.add_argument('--manpage-urls', required=True) p.add_argument('--revision', required=True) |