nixos-render-docs: generalize option converter

while we won't have other converters (with other output formats) for a
while yet it still seems like a good idea to generalize *now* so we have
a pattern to follow.
This commit is contained in:
pennae 2023-01-25 21:38:52 +01:00
parent ccb586299d
commit e0596e0940
2 changed files with 36 additions and 9 deletions

View File

@ -1,3 +1,4 @@
from abc import ABC
from collections.abc import Mapping, MutableMapping, Sequence
from frozendict import frozendict # type: ignore[attr-defined]
from typing import Any, Callable, Optional
@ -180,7 +181,7 @@ class Renderer(markdown_it.renderer.RendererProtocol):
env: MutableMapping[str, Any]) -> str:
raise RuntimeError("md token not supported", token)
class Converter:
class Converter(ABC):
__renderer__: Callable[[Mapping[str, str], markdown_it.MarkdownIt], Renderer]
def __init__(self, manpage_urls: Mapping[str, str]):

View File

@ -1,3 +1,4 @@
from abc import abstractmethod
from typing import Any, Optional
from xml.sax.saxutils import escape, quoteattr
@ -14,8 +15,7 @@ def option_is(option: Option, key: str, typ: str) -> Optional[dict[str, str]]:
return None
return option[key] # type: ignore[return-value]
class DocBookConverter(Converter):
__renderer__ = DocBookRenderer
class BaseConverter(Converter):
_options: dict[str, RenderedOption]
def __init__(self, manpage_urls: dict[str, str],
@ -59,6 +59,15 @@ class DocBookConverter(Converter):
else:
return (loc['url'] if 'url' in loc else None, loc['name'])
@abstractmethod
def _decl_def_header(self, header: str) -> list[str]: raise NotImplementedError()
@abstractmethod
def _decl_def_entry(self, href: Optional[str], name: str) -> list[str]: raise NotImplementedError()
@abstractmethod
def _decl_def_footer(self) -> list[str]: raise NotImplementedError()
def _render_decl_def(self, header: str, locs: list[OptionLoc]) -> list[str]:
result = []
result += self._decl_def_header(header)
@ -69,9 +78,7 @@ class DocBookConverter(Converter):
return result
def _render_code(self, option: Option, key: str) -> list[str]:
if lit := option_is(option, key, 'literalDocBook'):
return [ f"<para><emphasis>{key.capitalize()}:</emphasis> {lit['text']}</para>" ]
elif lit := option_is(option, key, 'literalMD'):
if lit := option_is(option, key, 'literalMD'):
return [ self._render(f"*{key.capitalize()}:*\n{lit['text']}") ]
elif lit := option_is(option, key, 'literalExpression'):
code = lit['text']
@ -93,15 +100,16 @@ class DocBookConverter(Converter):
return []
def _render_description(self, desc: str | dict[str, str]) -> list[str]:
if isinstance(desc, str) and not self._markdown_by_default:
return [ f"<nixos:option-description><para>{desc}</para></nixos:option-description>" ]
elif isinstance(desc, str) and self._markdown_by_default:
if isinstance(desc, str) and self._markdown_by_default:
return [ self._render(desc) ]
elif isinstance(desc, dict) and desc.get('_type') == 'mdDoc':
return [ self._render(desc['text']) ]
else:
raise Exception("description has unrecognized type", desc)
@abstractmethod
def _related_packages_header(self) -> list[str]: raise NotImplementedError()
def _convert_one(self, option: dict[str, Any]) -> list[str]:
result = []
@ -131,6 +139,24 @@ class DocBookConverter(Converter):
except Exception as e:
raise Exception(f"Failed to render option {name}") from e
@abstractmethod
def finalize(self) -> str: raise NotImplementedError()
class DocBookConverter(BaseConverter):
__renderer__ = DocBookRenderer
def _render_code(self, option: dict[str, Any], key: str) -> list[str]:
if lit := option_is(option, key, 'literalDocBook'):
return [ f"<para><emphasis>{key.capitalize()}:</emphasis> {lit['text']}</para>" ]
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:
return [ f"<nixos:option-description><para>{desc}</para></nixos:option-description>" ]
else:
return super()._render_description(desc)
def _related_packages_header(self) -> list[str]:
return [
"<para>",