Source code for pkgcore.util.rst2devbook

"""A docutils's writer for DevBook format [#]_

.. [#] https://devmanual.gentoo.org/appendices/devbook-guide/index.html
"""

from docutils import nodes, writers

import lxml.etree as etree


[docs] class DevBookWriter(writers.Writer): """A docutils writer for DevBook.""" def __init__(self, eclass): """Initialize the writer. Takes the root element of the resulting DocBook output as its sole argument.""" super().__init__() self.eclass = eclass
[docs] def translate(self): """Call the translator to translate the document""" self.visitor = DevBookTranslator(self.document, self.eclass) self.document.walkabout(self.visitor) self.output = self.visitor.astext()
[docs] class DevBookTranslator(nodes.NodeVisitor): """A docutils translator for DevBook.""" sections_tags = ("section", "subsection", "subsubsection") def __init__(self, document: nodes.document, eclass: str): super().__init__(document) self.eclass = eclass self.estack = [] self.tb = etree.TreeBuilder() self.section_depth = 0
[docs] def astext(self) -> str: doc = self.tb.close() et = etree.ElementTree(doc) return etree.tostring( et, encoding="utf-8", xml_declaration=True, pretty_print=True ).decode()
def _push_element(self, name: str, **kwargs): e = self.tb.start(name, kwargs) self.estack.append(e) return e def _pop_element(self): e = self.estack.pop() return self.tb.end(e.tag)
[docs] def visit_document(self, node): self.tb.start("guide", {"self": f"eclass-reference/{self.eclass}/"}) self.tb.start("chapter", {})
[docs] def depart_document(self, node): self.tb.end("chapter") self.tb.end("guide")
[docs] def visit_Text(self, node): self.tb.data(str(node).replace("\x00", ""))
[docs] def depart_Text(self, node): pass
[docs] def visit_paragraph(self, node): self._push_element("p")
[docs] def depart_paragraph(self, node): self._pop_element()
[docs] def visit_attribution(self, node): self._push_element("p")
[docs] def depart_attribution(self, node): self._pop_element()
[docs] def visit_literal_block(self, node): self._push_element("codesample", lang="ebuild")
[docs] def depart_literal_block(self, node): self._pop_element()
[docs] def visit_literal(self, node): self._push_element("c")
[docs] def depart_literal(self, node): self._pop_element()
[docs] def visit_emphasis(self, node): self._push_element("e")
[docs] def depart_emphasis(self, node): self._pop_element()
[docs] def visit_strong(self, node): self._push_element("b")
[docs] def depart_strong(self, node): self._pop_element()
[docs] def visit_block_quote(self, node): self._push_element("pre")
[docs] def depart_block_quote(self, node): self._pop_element()
[docs] def visit_title(self, node): self._push_element("title")
[docs] def depart_title(self, node): self._pop_element() if self.section_depth > 0: self._push_element("body")
[docs] def visit_section(self, node): if self.estack and self.estack[-1].tag == "body": self._pop_element() self._push_element(self.sections_tags[self.section_depth]) self.section_depth += 1
[docs] def depart_section(self, node): self.section_depth -= 1 if self.estack[-1].tag == "body": self._pop_element() self._pop_element()
[docs] def visit_title_reference(self, node): pass
[docs] def depart_title_reference(self, node): pass
[docs] def visit_reference(self, node): internal_ref = False # internal ref style #1: it declares itself internal if node.hasattr("internal"): internal_ref = node["internal"] # internal ref style #2: it hides as an external ref, with strange # qualities. if ( node.hasattr("anonymous") and (node["anonymous"] == 1) and node.hasattr("refuri") and (node["refuri"][0] == "_") ): internal_ref = True node["refuri"] = node["refuri"][1:] assert not internal_ref if node.hasattr("refid"): assert False self._push_element("link", {"linkend": node["refid"]}) elif node.hasattr("refuri"): if internal_ref: pass # ref_name = os.path.splitext(node['refuri'])[0] # self._push_element('link', {'linkend': ref_name}) else: self._push_element("uri", link=node["refuri"]) else: assert False
[docs] def depart_reference(self, node): if node.hasattr("refid") or node.hasattr("refuri"): self._pop_element()
[docs] def visit_bullet_list(self, node): self._push_element("ul")
[docs] def depart_bullet_list(self, node): self._pop_element()
[docs] def visit_enumerated_list(self, node): self._push_element("ol")
[docs] def depart_enumerated_list(self, node): self._pop_element()
[docs] def visit_list_item(self, node): self._push_element("li")
[docs] def depart_list_item(self, node): self._pop_element()
[docs] def visit_line_block(self, node): pass
[docs] def depart_line_block(self, node): pass
[docs] def visit_line(self, node): self._push_element("p")
[docs] def depart_line(self, node): self._pop_element()
# # Definitions list block #
[docs] def visit_definition_list(self, node): self._push_element("dl")
[docs] def depart_definition_list(self, node): self._pop_element()
[docs] def visit_definition_list_item(self, node): pass
[docs] def depart_definition_list_item(self, node): pass
[docs] def visit_term(self, node): self._push_element("dt")
[docs] def depart_term(self, node): self._pop_element()
[docs] def visit_definition(self, node): self._push_element("dd")
[docs] def depart_definition(self, node): self._pop_element()
### Debugging blocks
[docs] def visit_problematic(self, node): self._push_element("warning")
[docs] def depart_problematic(self, node): self._pop_element()
[docs] def visit_system_message(self, node): self._push_element("warning")
[docs] def depart_system_message(self, node): self._pop_element()