``."""
- return "\n" + text + "\n"
-
- def table(self, header, body):
- """Rendering table element. Wrap header and body in it.
-
- :param header: header part of the table.
- :param body: body part of the table.
- """
- table = "\n.. list-table::\n"
- if header and not header.isspace():
- table = (
- table
- + self.indent
- + ":header-rows: 1\n\n"
- + self._indent_block(header)
- + "\n"
- )
- else:
- table = table + "\n"
- table = table + self._indent_block(body) + "\n\n"
- return table
-
- def table_row(self, content):
- """Rendering a table row. Like ``
``.
-
- :param content: content of current table row.
- """
- contents = content.splitlines()
- if not contents:
- return ""
- clist = ["* " + contents[0]]
- if len(contents) > 1:
- for c in contents[1:]:
- clist.append(" " + c)
- return "\n".join(clist) + "\n"
-
- def table_cell(self, content, **flags):
- """Rendering a table cell. Like ```` `` | ``.
-
- :param content: content of current table cell.
- :param header: whether this is header or not.
- :param align: align of current table cell.
- """
- return "- " + content + "\n"
-
- def double_emphasis(self, text):
- """Rendering **strong** text.
-
- :param text: text content for emphasis.
- """
- return r"\ **{}**\ ".format(text)
-
- def emphasis(self, text):
- """Rendering *emphasis* text.
-
- :param text: text content for emphasis.
- """
- return r"\ *{}*\ ".format(text)
-
- def codespan(self, text):
- """Rendering inline `code` text.
-
- :param text: text content for inline code.
- """
- if "``" not in text:
- return r"\ ``{}``\ ".format(text)
- else:
- # actually, docutils split spaces in literal
- return self._raw_html(
- ''
- '{}'
- " ".format(text.replace("`", "`"))
- )
-
- def linebreak(self):
- """Rendering line break like `` ``."""
- if self.options.get("use_xhtml"):
- return self._raw_html(" ") + "\n"
- return self._raw_html(" ") + "\n"
-
- def strikethrough(self, text):
- """Rendering ~~strikethrough~~ text.
-
- :param text: text content for strikethrough.
- """
- return self._raw_html("{}".format(text))
-
- def text(self, text):
- """Rendering unformatted text.
-
- :param text: text content.
- """
- return text
-
- def autolink(self, link, is_email=False):
- """Rendering a given link or email address.
-
- :param link: link content or email address.
- :param is_email: whether this is an email or not.
- """
- return link
-
- def link(self, link, title, text):
- """Rendering a given link with content and title.
-
- :param link: href link for ```` tag.
- :param title: title content for `title` attribute.
- :param text: text content for description.
- """
- if self.anonymous_references:
- underscore = "__"
- else:
- underscore = "_"
- if title:
- return self._raw_html(
- '{text}'.format(
- link=link, title=title, text=text
- )
- )
- if not self.parse_relative_links:
- return r"\ `{text} <{target}>`{underscore}\ ".format(
- target=link, text=text, underscore=underscore
- )
- else:
- url_info = urlparse(link)
- if url_info.scheme:
- return r"\ `{text} <{target}>`{underscore}\ ".format(
- target=link, text=text, underscore=underscore
- )
- else:
- link_type = "doc"
- anchor = url_info.fragment
- if url_info.fragment:
- if url_info.path:
- # Can't link to anchors via doc directive.
- anchor = ""
- else:
- # Example: [text](#anchor)
- link_type = "ref"
- doc_link = "{doc_name}{anchor}".format(
- # splittext approach works whether or not path is set. It
- # will return an empty string if unset, which leads to
- # anchor only ref.
- doc_name=os.path.splitext(url_info.path)[0],
- anchor=anchor,
- )
- return r"\ :{link_type}:`{text} <{doc_link}>`\ ".format(
- link_type=link_type, doc_link=doc_link, text=text
- )
-
- def image(self, src, title, text):
- """Rendering a image with title and text.
-
- :param src: source link of the image.
- :param title: title text of the image.
- :param text: alt text of the image.
- """
- # rst does not support title option
- # and I couldn't find title attribute in HTML standard
- return "\n".join(
- [
- "",
- ".. image:: {}".format(src),
- " :target: {}".format(src),
- " :alt: {}".format(text),
- "",
- ]
- )
-
- def inline_html(self, html):
- """Rendering span level pure html content.
-
- :param html: text content of the html snippet.
- """
- return self._raw_html(html)
-
- def newline(self):
- """Rendering newline element."""
- return ""
-
- def footnote_ref(self, key, index):
- """Rendering the ref anchor of a footnote.
-
- :param key: identity key for the footnote.
- :param index: the index count of current footnote.
- """
- return r"\ [#fn-{}]_\ ".format(key)
-
- def footnote_item(self, key, text):
- """Rendering a footnote item.
-
- :param key: identity key for the footnote.
- :param text: text content of the footnote.
- """
- return ".. [#fn-{0}] {1}\n".format(key, text.strip())
-
- def footnotes(self, text):
- """Wrapper for all footnotes.
-
- :param text: contents of all footnotes.
- """
- if text:
- return "\n\n" + text
- else:
- return ""
-
- """Below outputs are for rst."""
-
- def image_link(self, url, target, alt):
- return "\n".join(
- [
- "",
- ".. image:: {}".format(url),
- " :target: {}".format(target),
- " :alt: {}".format(alt),
- "",
- ]
- )
-
- def rest_role(self, text):
- return text
-
- def rest_link(self, text):
- return text
-
- def inline_math(self, math):
- """Extension of recommonmark."""
- return r":math:`{}`".format(math)
-
- def eol_literal_marker(self, marker):
- """Extension of recommonmark."""
- return marker
-
- def directive(self, text):
- return "\n" + text
-
- def rest_code_block(self):
- return "\n\n"
-
-
-class M2R(mistune.Markdown):
- def __init__(
- self, renderer=None, inline=RestInlineLexer, block=RestBlockLexer, **kwargs
- ):
- if renderer is None:
- renderer = RestRenderer(**kwargs)
- super(M2R, self).__init__(renderer, inline=inline, block=block, **kwargs)
-
- def parse(self, text):
- output = super(M2R, self).parse(text)
- return self.post_process(output)
-
- def output_directive(self):
- return self.renderer.directive(self.token["text"])
-
- def output_rest_code_block(self):
- return self.renderer.rest_code_block()
-
- def post_process(self, text):
- output = (
- text.replace("\\ \n", "\n")
- .replace("\n\\ ", "\n")
- .replace(" \\ ", " ")
- .replace("\\ ", " ")
- .replace("\\ .", ".")
- )
- if self.renderer._include_raw_html:
- return prolog + output
- else:
- return output
-
-
-class M2RParser(rst.Parser, object):
- # Explicitly tell supported formats to sphinx
- supported = ("markdown", "md", "mkd")
-
- def parse(self, inputstrings, document):
- if isinstance(inputstrings, statemachine.StringList):
- inputstring = "\n".join(inputstrings)
- else:
- inputstring = inputstrings
- config = document.settings.env.config
- converter = M2R(
- no_underscore_emphasis=config.no_underscore_emphasis,
- parse_relative_links=config.m2r_parse_relative_links,
- anonymous_references=config.m2r_anonymous_references,
- disable_inline_math=config.m2r_disable_inline_math,
- use_mermaid=config.m2r_use_mermaid,
- )
- super(M2RParser, self).parse(converter(inputstring), document)
-
-
-class MdInclude(rst.Directive):
- """Directive class to include markdown in sphinx.
-
- Load a file and convert it to rst and insert as a node. Currently
- directive-specific options are not implemented.
- """
-
- required_arguments = 1
- optional_arguments = 0
- option_spec = {
- "start-line": int,
- "end-line": int,
- }
-
- def run(self):
- """Most of this method is from ``docutils.parser.rst.Directive``.
-
- docutils version: 0.12
- """
- if not self.state.document.settings.file_insertion_enabled:
- raise self.warning('"%s" directive disabled.' % self.name)
- source = self.state_machine.input_lines.source(
- self.lineno - self.state_machine.input_offset - 1
- )
- source_dir = os.path.dirname(os.path.abspath(source))
- path = rst.directives.path(self.arguments[0])
- path = os.path.normpath(os.path.join(source_dir, path))
- path = utils.relative_path(None, path)
- path = nodes.reprunicode(path)
-
- # get options (currently not use directive-specific options)
- encoding = self.options.get(
- "encoding", self.state.document.settings.input_encoding
- )
- e_handler = self.state.document.settings.input_encoding_error_handler
- tab_width = self.options.get(
- "tab-width", self.state.document.settings.tab_width
- )
-
- # open the including file
- try:
- self.state.document.settings.record_dependencies.add(path)
- include_file = io.FileInput(
- source_path=path, encoding=encoding, error_handler=e_handler
- )
- except UnicodeEncodeError:
- raise self.severe(
- 'Problems with "%s" directive path:\n'
- 'Cannot encode input file path "%s" '
- "(wrong locale?)." % (self.name, str(path))
- )
- except IOError as error:
- raise self.severe(
- 'Problems with "%s" directive path:\n%s.'
- % (self.name, io.error_string(error))
- )
-
- # read from the file
- startline = self.options.get("start-line", None)
- endline = self.options.get("end-line", None)
- try:
- if startline or (endline is not None):
- lines = include_file.readlines()
- rawtext = "".join(lines[startline:endline])
- else:
- rawtext = include_file.read()
- except UnicodeError as error:
- raise self.severe(
- 'Problem with "%s" directive:\n%s' % (self.name, io.error_string(error))
- )
-
- config = self.state.document.settings.env.config
- converter = M2R(
- no_underscore_emphasis=config.no_underscore_emphasis,
- parse_relative_links=config.m2r_parse_relative_links,
- anonymous_references=config.m2r_anonymous_references,
- disable_inline_math=config.m2r_disable_inline_math,
- use_mermaid=config.m2r_use_mermaid,
- )
- include_lines = statemachine.string2lines(
- converter(rawtext), tab_width, convert_whitespace=True
- )
- self.state_machine.insert_input(include_lines, path)
- return []
-
-
-def setup(app):
- """When used for sphinx extension."""
- global _is_sphinx
- _is_sphinx = True
- app.add_config_value("no_underscore_emphasis", False, "env")
- app.add_config_value("m2r_parse_relative_links", False, "env")
- app.add_config_value("m2r_anonymous_references", False, "env")
- app.add_config_value("m2r_disable_inline_math", False, "env")
- app.add_config_value(
- "m2r_use_mermaid", "sphinxcontrib.mermaid" in app.config.extensions, "env"
- )
- try:
- app.add_source_parser(".md", M2RParser) # for older sphinx versions
- except (TypeError, AttributeError):
- app.add_source_suffix(".md", "markdown")
- app.add_source_parser(M2RParser)
- app.add_directive("mdinclude", MdInclude)
- metadata = dict(
- version=__version__,
- parallel_read_safe=True,
- parallel_write_safe=True,
- )
- return metadata
-
-
-def convert(text, **kwargs):
- return M2R(**kwargs)(text)
-
-
-def parse_from_file(file, encoding="utf-8", **kwargs):
- if not os.path.exists(file):
- raise OSError("No such file exists: {}".format(file))
- with _open(file, encoding=encoding) as f:
- src = f.read()
- output = convert(src, **kwargs)
- return output
-
-
-def save_to_file(file, src, encoding="utf-8", **kwargs):
- target = os.path.splitext(file)[0] + ".rst"
- if not options.overwrite and os.path.exists(target):
- confirm = input("{} already exists. overwrite it? [y/n]: ".format(target))
- if confirm.upper() not in ("Y", "YES"):
- print("skip {}".format(file))
- return
- with _open(target, "w", encoding=encoding) as f:
- f.write(src)
-
-
-def main():
- parse_options() # parse cli options
- if not options.input_file:
- parser.print_help()
- parser.exit(0)
- for file in options.input_file:
- output = parse_from_file(file)
- if options.dry_run:
- print(output)
- else:
- save_to_file(file, output)
-
-
-if __name__ == "__main__":
- main()
diff --git a/m2r2/__init__.py b/m2r2/__init__.py
new file mode 100644
index 0000000..6873e9b
--- /dev/null
+++ b/m2r2/__init__.py
@@ -0,0 +1,9 @@
+from .constants import *
+from .typing import *
+from .rst_parser import *
+from .rst_renderer import *
+from .m2r2 import M2R, convert
+from .sphinx_m2r2 import setup
+
+
+# __all__ = ("M2R", "convert", "setup", "rst")
diff --git a/m2r2/cli/__init__.py b/m2r2/cli/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/m2r2/cli/m2r2.py b/m2r2/cli/m2r2.py
new file mode 100644
index 0000000..f13a6fd
--- /dev/null
+++ b/m2r2/cli/m2r2.py
@@ -0,0 +1,85 @@
+import os
+from argparse import ArgumentParser, Namespace
+
+from ..m2r2 import convert
+
+parser = ArgumentParser()
+options = Namespace()
+parser.add_argument("input_file", nargs="*", help="files to convert to reST format")
+parser.add_argument(
+ "--overwrite",
+ action="store_true",
+ default=False,
+ help="overwrite output file without confirmaion",
+)
+parser.add_argument(
+ "--dry-run",
+ action="store_true",
+ default=False,
+ help="print conversion result and not save output file",
+)
+parser.add_argument(
+ "--no-underscore-emphasis",
+ action="store_true",
+ default=False,
+ help="do not use underscore (_) for emphasis",
+)
+parser.add_argument(
+ "--parse-relative-links",
+ action="store_true",
+ default=False,
+ help="parse relative links into ref or doc directives",
+)
+parser.add_argument(
+ "--anonymous-references",
+ action="store_true",
+ default=False,
+ help="use anonymous references in generated rst",
+)
+parser.add_argument(
+ "--disable-inline-math",
+ action="store_true",
+ default=False,
+ help="disable parsing inline math",
+)
+
+
+def parse_options():
+ parser.parse_known_args(namespace=options)
+
+
+def parse_from_file(file, encoding="utf-8", **kwargs):
+ if not os.path.exists(file):
+ raise OSError("No such file exists: {}".format(file))
+ with open(file, encoding=encoding) as f:
+ src = f.read()
+ output = convert(src, **kwargs)
+ return output
+
+
+def save_to_file(file, src, encoding="utf-8", **kwargs):
+ target = os.path.splitext(file)[0] + ".rst"
+ if not options.overwrite and os.path.exists(target):
+ confirm = input("{} already exists. overwrite it? [y/n]: ".format(target))
+ if confirm.upper() not in ("Y", "YES"):
+ print("skip {}".format(file))
+ return
+ with open(target, "w", encoding=encoding) as f:
+ f.write(src)
+
+
+def main():
+ parse_options() # parse cli options
+ if not options.input_file:
+ parser.print_help()
+ parser.exit(0)
+ for file in options.input_file:
+ output = parse_from_file(file)
+ if options.dry_run:
+ print(output)
+ else:
+ save_to_file(file, output)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/m2r2/constants.py b/m2r2/constants.py
new file mode 100644
index 0000000..476f591
--- /dev/null
+++ b/m2r2/constants.py
@@ -0,0 +1,5 @@
+PROLOG = """\
+.. role:: raw-html-m2r(raw)
+ :format: html
+
+"""
diff --git a/m2r2/directives.py b/m2r2/directives.py
new file mode 100644
index 0000000..4d8df23
--- /dev/null
+++ b/m2r2/directives.py
@@ -0,0 +1,92 @@
+import os
+
+from docutils import io, nodes, statemachine, utils
+from docutils.parsers import rst
+
+from .m2r2 import M2R
+
+
+class MdInclude(rst.Directive):
+ """Directive class to include markdown in sphinx.
+
+ Load a file and convert it to rst and insert as a node. Currently
+ directive-specific options are not implemented.
+ """
+
+ required_arguments = 1
+ optional_arguments = 0
+ option_spec = {
+ "start-line": int,
+ "end-line": int,
+ }
+
+ def run(self):
+ """Most of this method is from ``docutils.parser.rst.Directive``.
+
+ docutils version: 0.12
+ """
+ if not self.state.document.settings.file_insertion_enabled:
+ raise self.warning('"%s" directive disabled.' % self.name)
+ source = self.state_machine.input_lines.source(
+ self.lineno - self.state_machine.input_offset - 1
+ )
+ source_dir = os.path.dirname(os.path.abspath(source))
+ path = rst.directives.path(self.arguments[0])
+ path = os.path.normpath(os.path.join(source_dir, path))
+ path = utils.relative_path(None, path)
+ path = nodes.reprunicode(path)
+
+ # get options (currently not use directive-specific options)
+ encoding = self.options.get(
+ "encoding", self.state.document.settings.input_encoding
+ )
+ e_handler = self.state.document.settings.input_encoding_error_handler
+ tab_width = self.options.get(
+ "tab-width", self.state.document.settings.tab_width
+ )
+
+ # open the including file
+ try:
+ self.state.document.settings.record_dependencies.add(path)
+ include_file = io.FileInput(
+ source_path=path, encoding=encoding, error_handler=e_handler
+ )
+ except UnicodeEncodeError:
+ raise self.severe(
+ 'Problems with "%s" directive path:\n'
+ 'Cannot encode input file path "%s" '
+ "(wrong locale?)." % (self.name, str(path))
+ )
+ except IOError as error:
+ raise self.severe(
+ 'Problems with "%s" directive path:\n%s.'
+ # % (self.name, io.error_string(error))
+ )
+
+ # read from the file
+ startline = self.options.get("start-line", None)
+ endline = self.options.get("end-line", None)
+ try:
+ if startline or (endline is not None):
+ lines = include_file.readlines()
+ rawtext = "".join(lines[startline:endline])
+ else:
+ rawtext = include_file.read()
+ except UnicodeError as error:
+ raise self.severe(
+ 'Problem with "%s" directive:\n%s' % (self.name, io.error_string(error))
+ )
+
+ # config = self.state.document.settings.env.config
+ converter = M2R(
+ # no_underscore_emphasis=config.no_underscore_emphasis,
+ # parse_relative_links=config.m2r_parse_relative_links,
+ # anonymous_references=config.m2r_anonymous_references,
+ # disable_inline_math=config.m2r_disable_inline_math,
+ # use_mermaid=config.m2r_use_mermaid,
+ )
+ include_lines = statemachine.string2lines(
+ converter(rawtext), tab_width, convert_whitespace=True
+ )
+ self.state_machine.insert_input(include_lines, path)
+ return []
diff --git a/m2r2/m2r2.py b/m2r2/m2r2.py
new file mode 100644
index 0000000..fbee1b8
--- /dev/null
+++ b/m2r2/m2r2.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+from __future__ import print_function, unicode_literals
+import mistune
+from pkg_resources import get_distribution
+from .constants import PROLOG
+from .rst_parser import RestBlockParser, RestInlineParser
+from .rst_renderer import RestRenderer
+
+__version__ = get_distribution("m2r2").version
+
+print("at M2R")
+
+class M2R(mistune.Markdown):
+ def __init__(self, renderer=None, block=None, inline=None, plugins=None):
+ renderer = renderer or RestRenderer()
+ block = block or RestBlockParser()
+ inline = inline or RestInlineParser(renderer)
+ super().__init__(renderer=renderer, block=block, inline=inline, plugins=plugins)
+
+ def parse(self, text):
+ output = super().parse(text)
+ return self.post_process(output)
+
+ def post_process(self, text):
+ output = (
+ text.replace("\\ \n", "\n")
+ .replace("\n\\ ", "\n")
+ .replace(" \\ ", " ")
+ .replace("\\ ", " ")
+ .replace("\\ .", ".")
+ )
+ if self.renderer._include_raw_html:
+ return PROLOG + output
+ else:
+ return output
+
+
+def convert(text, **kwargs):
+ return M2R(**kwargs)(text)
diff --git a/m2r2/parser.py b/m2r2/parser.py
new file mode 100644
index 0000000..c17c435
--- /dev/null
+++ b/m2r2/parser.py
@@ -0,0 +1,24 @@
+from docutils import statemachine
+from docutils.parsers import rst
+
+from .m2r2 import M2R
+
+
+class M2RParser(rst.Parser):
+ # Explicitly tell supported formats to sphinx
+ supported = ("markdown", "md", "mkd")
+
+ def parse(self, inputstrings, document):
+ if isinstance(inputstrings, statemachine.StringList):
+ inputstring = "\n".join(inputstrings)
+ else:
+ inputstring = inputstrings
+ # config = document.settings.env.config
+ converter = M2R(
+ # no_underscore_emphasis=config.no_underscore_emphasis,
+ # parse_relative_links=config.m2r_parse_relative_links,
+ # anonymous_references=config.m2r_anonymous_references,
+ # disable_inline_math=config.m2r_disable_inline_math,
+ # use_mermaid=config.m2r_use_mermaid,
+ )
+ super(M2RParser, self).parse(converter(inputstring), document)
diff --git a/m2r2/rst_parser.py b/m2r2/rst_parser.py
new file mode 100644
index 0000000..384800a
--- /dev/null
+++ b/m2r2/rst_parser.py
@@ -0,0 +1,126 @@
+import re
+from typing import Match
+
+import mistune
+
+from m2r2.typing import Element, State, Token
+
+# TODO: fix global
+_is_sphinx = False
+
+
+class RestBlockParser(mistune.BlockParser):
+ DIRECTIVE = re.compile(
+ r"^( *\.\..*?)\n(?=\S)",
+ re.DOTALL | re.MULTILINE,
+ )
+ ONELINE_DIRECTIVE = re.compile(
+ r"^( *\.\..*?)$",
+ re.DOTALL | re.MULTILINE,
+ )
+ REST_CODE_BLOCK = re.compile(
+ r"^::\s*$",
+ re.DOTALL | re.MULTILINE,
+ )
+ RULE_NAMES = mistune.BlockParser.RULE_NAMES + (
+ "directive",
+ "oneline_directive",
+ "rest_code_block",
+ )
+
+ RULE_NAMES = (
+ "directive",
+ "oneline_directive",
+ "rest_code_block",
+ ) + mistune.BlockParser.RULE_NAMES
+
+ def parse_directive(self, match: Match, state: State) -> Token:
+ return {"type": "directive", "text": match.group(1)}
+
+ def parse_oneline_directive(self, match: Match, state: State) -> Token:
+ # reuse directive output
+ return {"type": "directive", "text": match.group(1)}
+
+ def parse_rest_code_block(self, match: Match, state: State) -> Token:
+ return {"type": "rest_code_block", "text": ""}
+
+
+class RestInlineParser(mistune.InlineParser):
+ IMAGE_LINK = re.compile(
+ r"\[!\[(?P.*?)\]\((?P.*?)\).*?\]\((?P.*?)\)"
+ )
+ REST_ROLE = re.compile(r":.*?:`.*?`|`[^`]+`:.*?:")
+ REST_LINK = re.compile(r"`[^`]*?`_")
+ INLINE_MATH = re.compile(r"`\$(.*?)\$`")
+ EOL_LITERAL_MARKER = re.compile(r"(\s+)?::\s*$")
+ # add colon and space as special text
+ TEXT = re.compile(r"^[\s\S]+?(?=[\\[\s\S]+?)\1{2}(?!\1)")
+ # _word_ or *word*
+ EMPHASIS = re.compile(
+ r"^\b_((?:__|[^_])+?)_\b" # _word_
+ r"|"
+ r"^\*(?P(?:\*\*|[^\*])+?)\*(?!\*)" # *word*
+ )
+
+ RUlE_NAMES = (
+ "inline_math",
+ "image_link",
+ "rest_role",
+ "rest_link",
+ "eol_literal_marker",
+ ) + mistune.InlineParser.RULE_NAMES
+
+ def parse_double_emphasis(self, match: Match, state: State) -> Element:
+ # may include code span
+ return "double_emphasis", match.group("text")
+
+ def parse_emphasis(self, match: Match, state: State) -> Element:
+ # may include code span
+ return "emphasis", match.group("text") or match.group(1)
+
+ def parse_image_link(self, match: Match, state: State) -> Element:
+ """Pass through rest role."""
+ alt, src, target = match.groups()
+ return "image_link", src, target, alt
+
+ def parse_rest_role(self, match: Match, state: State) -> Element:
+ """Pass through rest role."""
+ return "rest_role", match.group(0)
+
+ def parse_rest_link(self, match: Match, state: State) -> Element:
+ """Pass through rest link."""
+ return "rest_link", match.group(0)
+
+ def parse_inline_math(self, match: Match, state: State) -> Element:
+ """Pass through rest link."""
+ return "inline_math", match.group(2)
+
+ def parse_eol_literal_marker(self, match: Match, state: State) -> Element:
+ """Pass through rest link."""
+ marker = ":" if match.group(1) is None else ""
+ return "eol_literal_marker", marker
+
+ def no_underscore_emphasis(self):
+ self.DOUBLE_EMPHASIS = re.compile(
+ r"^\*{2}(?P[\s\S]+?)\*{2}(?!\*)" # **word**
+ )
+ self.EMPHASIS = re.compile(r"^\*(?P(?:\*\*|[^\*])+?)\*(?!\*)") # *word*
+
+ def __init__(self, renderer, *args, **kwargs):
+ # no_underscore_emphasis = kwargs.pop("no_underscore_emphasis", False)
+ disable_inline_math = kwargs.pop("disable_inline_math", False)
+ super().__init__(renderer, *args, **kwargs)
+ # if not _is_sphinx:
+ # parse_options()
+ # if no_underscore_emphasis or getattr(options, "no_underscore_emphasis", False):
+ # self.rules.no_underscore_emphasis()
+ inline_maths = "inline_math" in self.RULE_NAMES
+ if disable_inline_math: # or getattr(options, "disable_inline_math", False):
+ if inline_maths:
+ self.RULE_NAMES = tuple(
+ x for x in self.RUlE_NAMES if x != "inline_math"
+ )
+ elif not inline_maths:
+ self.RUlE_NAMES = ("inline_math", *self.RUlE_NAMES)
diff --git a/m2r2/rst_renderer.py b/m2r2/rst_renderer.py
new file mode 100644
index 0000000..9326829
--- /dev/null
+++ b/m2r2/rst_renderer.py
@@ -0,0 +1,355 @@
+import os
+from urllib.parse import urlparse
+
+from docutils.utils import column_width
+from mistune.renderers import BaseRenderer
+
+_is_sphinx = False
+
+
+class RestRenderer(BaseRenderer):
+ _include_raw_html = False
+ # list_indent_re = re.compile(r"^(\s*(#\.|\*)\s)")
+ indent = " " * 3
+ list_marker = "{#__rest_list_mark__#}"
+ hmarks = {
+ 1: "=",
+ 2: "-",
+ 3: "^",
+ 4: "~",
+ 5: '"',
+ 6: "#",
+ }
+
+ def __init__(self, *args, **kwargs):
+ self.parse_relative_links = kwargs.pop("parse_relative_links", False)
+ self.anonymous_references = kwargs.pop("anonymous_references", False)
+ self.use_mermaid = kwargs.pop("use_mermaid", False)
+ super(RestRenderer, self).__init__(*args, **kwargs)
+ # if not _is_sphinx:
+ # parse_options()
+ # if getattr(options, "parse_relative_links", False):
+ # self.parse_relative_links = options.parse_relative_links
+ # if getattr(options, "anonymous_references", False):
+ # self.anonymous_references = options.anonymous_references
+
+ def finalize(self, data):
+ return "".join(filter(lambda x: x is not None, data))
+
+ def _indent_block(self, block):
+ return "\n".join(
+ self.indent + line if line else "" for line in block.splitlines()
+ )
+
+ def _raw_html(self, html):
+ self._include_raw_html = True
+ return r"\ :raw-html-m2r:`{}`\ ".format(html)
+
+ def block_code(self, code, lang=None):
+ if lang == "math":
+ first_line = "\n.. math::\n\n"
+ elif lang == "mermaid" and self.use_mermaid:
+ first_line = "\n.. mermaid::\n\n"
+ elif lang:
+ first_line = "\n.. code-block:: {}\n\n".format(lang)
+ elif _is_sphinx:
+ first_line = "\n::\n\n"
+ else:
+ first_line = "\n.. code-block::\n\n"
+ return first_line + self._indent_block(code) + "\n"
+
+ def block_quote(self, text):
+ # text includes some empty line
+ return "\n..\n\n{}\n\n".format(self._indent_block(text.strip("\n")))
+
+ def block_text(self, text):
+ return text
+
+ def block_html(self, html):
+ """Rendering block level pure html content.
+
+ :param html: text content of the html snippet.
+ """
+ return "\n\n.. raw:: html\n\n" + self._indent_block(html) + "\n\n"
+
+ def header(self, text, level, raw=None):
+ """Rendering header/heading tags like `` |