diff --git a/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/__init__.py b/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/__init__.py index abd794039710..b4fd100a1f70 100644 --- a/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/__init__.py +++ b/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/__init__.py @@ -21,6 +21,8 @@ from .md import md_escape class Converter: def __init__(self, manpage_urls: Dict[str, str]): + self._manpage_urls = frozendict(manpage_urls) + self._md = markdown_it.MarkdownIt( "commonmark", { @@ -28,7 +30,7 @@ class Converter: 'html': False, # not useful since we target many formats 'typographer': True, # required for smartquotes }, - renderer_cls=DocBookRenderer + renderer_cls=lambda parser: DocBookRenderer(self._manpage_urls, parser) ) # TODO maybe fork the plugin and have only a single rule for all? self._md.use(container_plugin, name="{.note}") @@ -38,13 +40,8 @@ class Converter: self._md.use(myst_role_plugin) self._md.enable(["smartquotes", "replacements"]) - self._manpage_urls = frozendict(manpage_urls) - def render(self, src: str) -> str: - env = { - 'manpage_urls': self._manpage_urls - } - return self._md.render(src, env) + return self._md.render(src) md = Converter(json.load(open(os.getenv('MANPAGE_URLS')))) diff --git a/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/docbook.py b/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/docbook.py index dddfa13dfdc3..ef627fd7318d 100644 --- a/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/docbook.py +++ b/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/docbook.py @@ -1,6 +1,6 @@ -from collections.abc import MutableMapping, Sequence +from collections.abc import Mapping, MutableMapping, Sequence from frozendict import frozendict # type: ignore[attr-defined] -from typing import Any, Optional +from typing import Any, cast, Optional import markdown_it from markdown_it.token import Token @@ -22,15 +22,19 @@ _xml_id_translate_table = { def make_xml_id(s: str) -> str: return s.translate(_xml_id_translate_table) +class Deflist: + has_dd = False + class DocBookRenderer(Renderer): __output__ = "docbook" - def render(self, tokens: Sequence[Token], options: OptionsDict, - env: MutableMapping[str, Any]) -> str: - assert '-link-tag-stack' not in env - env['-link-tag-stack'] = [] - assert '-deflist-stack' not in env - env['-deflist-stack'] = [] - return super().render(tokens, options, env) + _link_tags: list[str] + _deflists: list[Deflist] + + def __init__(self, manpage_urls: Mapping[str, str], parser: Optional[markdown_it.MarkdownIt] = None): + super().__init__(manpage_urls, parser) + self._link_tags = [] + self._deflists = [] + def renderInline(self, tokens: Sequence[Token], options: OptionsDict, env: MutableMapping[str, Any]) -> str: # HACK to support docbook links and xrefs. link handling is only necessary because the docbook @@ -72,12 +76,13 @@ class DocBookRenderer(Renderer): return f"{escape(token.content)}" def link_open(self, token: Token, tokens: Sequence[Token], i: int, options: OptionsDict, env: MutableMapping[str, Any]) -> str: - env['-link-tag-stack'].append(token.tag) - (attr, start) = ('linkend', 1) if token.attrs['href'][0] == '#' else ('xlink:href', 0) - return f"<{token.tag} {attr}={quoteattr(token.attrs['href'][start:])}>" + self._link_tags.append(token.tag) + href = cast(str, token.attrs['href']) + (attr, start) = ('linkend', 1) if href[0] == '#' else ('xlink:href', 0) + return f"<{token.tag} {attr}={quoteattr(href[start:])}>" def link_close(self, token: Token, tokens: Sequence[Token], i: int, options: OptionsDict, env: MutableMapping[str, Any]) -> str: - return f"" + return f"" def list_item_open(self, token: Token, tokens: Sequence[Token], i: int, options: OptionsDict, env: MutableMapping[str, Any]) -> str: return "" @@ -137,24 +142,24 @@ class DocBookRenderer(Renderer): # we have to reject multiple definitions for the same term for time being. def dl_open(self, token: Token, tokens: Sequence[Token], i: int, options: OptionsDict, env: MutableMapping[str, Any]) -> str: - env['-deflist-stack'].append({}) + self._deflists.append(Deflist()) return "" def dl_close(self, token: Token, tokens: Sequence[Token], i: int, options: OptionsDict, env: MutableMapping[str, Any]) -> str: - env['-deflist-stack'].pop() + self._deflists.pop() return "" def dt_open(self, token: Token, tokens: Sequence[Token], i: int, options: OptionsDict, env: MutableMapping[str, Any]) -> str: - env['-deflist-stack'][-1]['has-dd'] = False + self._deflists[-1].has_dd = False return "" def dt_close(self, token: Token, tokens: Sequence[Token], i: int, options: OptionsDict, env: MutableMapping[str, Any]) -> str: return "" def dd_open(self, token: Token, tokens: Sequence[Token], i: int, options: OptionsDict, env: MutableMapping[str, Any]) -> str: - if env['-deflist-stack'][-1]['has-dd']: + if self._deflists[-1].has_dd: raise Exception("multiple definitions per term not supported") - env['-deflist-stack'][-1]['has-dd'] = True + self._deflists[-1].has_dd = True return "" def dd_close(self, token: Token, tokens: Sequence[Token], i: int, options: OptionsDict, env: MutableMapping[str, Any]) -> str: @@ -178,8 +183,8 @@ class DocBookRenderer(Renderer): title = f"{escape(page)}" vol = f"{escape(section)}" ref = f"{title}{vol}" - if man in env['manpage_urls']: - return f"{ref}" + if man in self._manpage_urls: + return f"{ref}" else: return ref raise NotImplementedError("md node not supported yet", token) diff --git a/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/md.py b/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/md.py index 93bd68c51a6f..01e9659ce27e 100644 --- a/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/md.py +++ b/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/md.py @@ -1,4 +1,4 @@ -from collections.abc import MutableMapping, Sequence +from collections.abc import Mapping, MutableMapping, Sequence from typing import Any, Optional import markdown_it @@ -19,7 +19,8 @@ def md_escape(s: str) -> str: return s.translate(_md_escape_table) class Renderer(markdown_it.renderer.RendererProtocol): - def __init__(self, parser: Optional[markdown_it.MarkdownIt] = None): + def __init__(self, manpage_urls: Mapping[str, str], parser: Optional[markdown_it.MarkdownIt] = None): + self._manpage_urls = manpage_urls self.rules = { 'text': self.text, 'paragraph_open': self.paragraph_open,