| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- from textwrap import indent
- from typing import Any, Dict, Iterable, List, cast
- from ..core import BaseRenderer, BlockState
- from ..util import strip_end
- from ._list import render_list
- class RSTRenderer(BaseRenderer):
- """A renderer for converting Markdown to ReST."""
- NAME = "rst"
- #: marker symbols for heading
- HEADING_MARKERS = {
- 1: "=",
- 2: "-",
- 3: "~",
- 4: "^",
- 5: '"',
- 6: "'",
- }
- INLINE_IMAGE_PREFIX = "img-"
- def iter_tokens(self, tokens: Iterable[Dict[str, Any]], state: BlockState) -> Iterable[str]:
- prev = None
- for tok in tokens:
- # ignore blank line
- if tok["type"] == "blank_line":
- continue
- tok["prev"] = prev
- prev = tok
- yield self.render_token(tok, state)
- def __call__(self, tokens: Iterable[Dict[str, Any]], state: BlockState) -> str:
- state.env["inline_images"] = []
- out = self.render_tokens(tokens, state)
- # special handle for line breaks
- out += "\n\n".join(self.render_referrences(state)) + "\n"
- return strip_end(out)
- def render_referrences(self, state: BlockState) -> Iterable[str]:
- images = state.env["inline_images"]
- for index, token in enumerate(images):
- attrs = token["attrs"]
- alt = self.render_children(token, state)
- ident = self.INLINE_IMAGE_PREFIX + str(index)
- yield ".. |" + ident + "| image:: " + attrs["url"] + "\n :alt: " + alt
- def render_children(self, token: Dict[str, Any], state: BlockState) -> str:
- children = token["children"]
- return self.render_tokens(children, state)
- def text(self, token: Dict[str, Any], state: BlockState) -> str:
- text = cast(str, token["raw"])
- return text.replace("|", r"\|")
- def emphasis(self, token: Dict[str, Any], state: BlockState) -> str:
- return "*" + self.render_children(token, state) + "*"
- def strong(self, token: Dict[str, Any], state: BlockState) -> str:
- return "**" + self.render_children(token, state) + "**"
- def link(self, token: Dict[str, Any], state: BlockState) -> str:
- attrs = token["attrs"]
- text = self.render_children(token, state)
- return "`" + text + " <" + cast(str, attrs["url"]) + ">`__"
- def image(self, token: Dict[str, Any], state: BlockState) -> str:
- refs: List[Dict[str, Any]] = state.env["inline_images"]
- index = len(refs)
- refs.append(token)
- return "|" + self.INLINE_IMAGE_PREFIX + str(index) + "|"
- def codespan(self, token: Dict[str, Any], state: BlockState) -> str:
- return "``" + cast(str, token["raw"]) + "``"
- def linebreak(self, token: Dict[str, Any], state: BlockState) -> str:
- return "<linebreak>"
- def softbreak(self, token: Dict[str, Any], state: BlockState) -> str:
- return " "
- def inline_html(self, token: Dict[str, Any], state: BlockState) -> str:
- # rst does not support inline html
- return ""
- def paragraph(self, token: Dict[str, Any], state: BlockState) -> str:
- children = token["children"]
- if len(children) == 1 and children[0]["type"] == "image":
- image = children[0]
- attrs = image["attrs"]
- title = cast(str, attrs.get("title"))
- alt = self.render_children(image, state)
- text = ".. figure:: " + cast(str, attrs["url"])
- if title:
- text += "\n :alt: " + title
- text += "\n\n" + indent(alt, " ")
- else:
- text = self.render_tokens(children, state)
- lines = text.split("<linebreak>")
- if len(lines) > 1:
- text = "\n".join("| " + line for line in lines)
- return text + "\n\n"
- def heading(self, token: Dict[str, Any], state: BlockState) -> str:
- attrs = token["attrs"]
- text = self.render_children(token, state)
- marker = self.HEADING_MARKERS[attrs["level"]]
- return text + "\n" + marker * len(text) + "\n\n"
- def thematic_break(self, token: Dict[str, Any], state: BlockState) -> str:
- return "--------------\n\n"
- def block_text(self, token: Dict[str, Any], state: BlockState) -> str:
- return self.render_children(token, state) + "\n"
- def block_code(self, token: Dict[str, Any], state: BlockState) -> str:
- attrs = token.get("attrs", {})
- info = cast(str, attrs.get("info"))
- code = indent(cast(str, token["raw"]), " ")
- if info:
- lang = info.split()[0]
- return ".. code:: " + lang + "\n\n" + code + "\n"
- else:
- return "::\n\n" + code + "\n\n"
- def block_quote(self, token: Dict[str, Any], state: BlockState) -> str:
- text = indent(self.render_children(token, state), " ")
- prev = token["prev"]
- ignore_blocks = (
- "paragraph",
- "thematic_break",
- "linebreak",
- "heading",
- )
- if prev and prev["type"] not in ignore_blocks:
- text = "..\n\n" + text
- return text
- def block_html(self, token: Dict[str, Any], state: BlockState) -> str:
- raw = token["raw"]
- return ".. raw:: html\n\n" + indent(raw, " ") + "\n\n"
- def block_error(self, token: Dict[str, Any], state: BlockState) -> str:
- return ""
- def list(self, token: Dict[str, Any], state: BlockState) -> str:
- return render_list(self, token, state)
|