···
from typing import Any, Dict, List
9
+
from xml.sax.saxutils import escape, quoteattr
···
result[opt.name] = opt.value
44
-
# converts in-place!
45
-
def convertMD(options: Dict[str, Any]) -> str:
48
-
from xml.sax.saxutils import escape, quoteattr
50
+
'.warning': 'warning',
51
+
'.important': 'important',
54
+
class Renderer(mistune.renderers.BaseRenderer):
55
+
def _get_method(self, name):
57
+
return super(Renderer, self)._get_method(name)
58
+
except AttributeError:
59
+
def not_supported(*args, **kwargs):
60
+
raise NotImplementedError("md node not supported yet", name, args, **kwargs)
61
+
return not_supported
51
-
'.warning': 'warning',
52
-
'.important': 'important',
55
-
class Renderer(mistune.renderers.BaseRenderer):
56
-
def __init__(self, path):
58
-
def _get_method(self, name):
60
-
return super(Renderer, self)._get_method(name)
61
-
except AttributeError:
62
-
def not_supported(*args, **kwargs):
63
-
raise NotImplementedError("md node not supported yet", self.path, name, args, **kwargs)
64
-
return not_supported
66
-
def text(self, text):
68
-
def paragraph(self, text):
69
-
return text + "\n\n"
71
-
return "<literallayout>\n</literallayout>"
72
-
def codespan(self, text):
73
-
return f"<literal>{escape(text)}</literal>"
74
-
def block_code(self, text, info=None):
75
-
info = f" language={quoteattr(info)}" if info is not None else ""
76
-
return f"<programlisting{info}>\n{escape(text)}</programlisting>"
77
-
def link(self, link, text=None, title=None):
78
-
if link[0:1] == '#':
80
-
link = quoteattr(link[1:])
82
-
# try to faithfully reproduce links that were of the form <link href="..."/>
87
-
link = quoteattr(link)
88
-
return f"<link {attr}={link}>{text}</link>"
89
-
def list(self, text, ordered, level, start=None):
91
-
raise NotImplementedError("ordered lists not supported yet")
92
-
return f"<itemizedlist>\n{text}\n</itemizedlist>"
93
-
def list_item(self, text, level):
94
-
return f"<listitem><para>{text}</para></listitem>\n"
95
-
def block_text(self, text):
97
-
def emphasis(self, text):
98
-
return f"<emphasis>{text}</emphasis>"
99
-
def strong(self, text):
100
-
return f"<emphasis role=\"strong\">{text}</emphasis>"
101
-
def admonition(self, text, kind):
102
-
if kind not in admonitions:
103
-
raise NotImplementedError(f"admonition {kind} not supported yet")
104
-
tag = admonitions[kind]
105
-
# we don't keep whitespace here because usually we'll contain only
106
-
# a single paragraph and the original docbook string is no longer
107
-
# available to restore the trailer.
108
-
return f"<{tag}><para>{text.rstrip()}</para></{tag}>"
109
-
def block_quote(self, text):
110
-
return f"<blockquote><para>{text}</para></blockquote>"
111
-
def command(self, text):
112
-
return f"<command>{escape(text)}</command>"
113
-
def option(self, text):
114
-
return f"<option>{escape(text)}</option>"
115
-
def file(self, text):
116
-
return f"<filename>{escape(text)}</filename>"
117
-
def manpage(self, page, section):
118
-
title = f"<refentrytitle>{escape(page)}</refentrytitle>"
119
-
vol = f"<manvolnum>{escape(section)}</manvolnum>"
120
-
return f"<citerefentry>{title}{vol}</citerefentry>"
122
-
def finalize(self, data):
123
-
return "".join(data)
63
+
def text(self, text):
65
+
def paragraph(self, text):
66
+
return text + "\n\n"
68
+
return "<literallayout>\n</literallayout>"
69
+
def codespan(self, text):
70
+
return f"<literal>{escape(text)}</literal>"
71
+
def block_code(self, text, info=None):
72
+
info = f" language={quoteattr(info)}" if info is not None else ""
73
+
return f"<programlisting{info}>\n{escape(text)}</programlisting>"
74
+
def link(self, link, text=None, title=None):
75
+
if link[0:1] == '#':
77
+
link = quoteattr(link[1:])
79
+
# try to faithfully reproduce links that were of the form <link href="..."/>
84
+
link = quoteattr(link)
85
+
return f"<link {attr}={link}>{text}</link>"
86
+
def list(self, text, ordered, level, start=None):
88
+
raise NotImplementedError("ordered lists not supported yet")
89
+
return f"<itemizedlist>\n{text}\n</itemizedlist>"
90
+
def list_item(self, text, level):
91
+
return f"<listitem><para>{text}</para></listitem>\n"
92
+
def block_text(self, text):
94
+
def emphasis(self, text):
95
+
return f"<emphasis>{text}</emphasis>"
96
+
def strong(self, text):
97
+
return f"<emphasis role=\"strong\">{text}</emphasis>"
98
+
def admonition(self, text, kind):
99
+
if kind not in admonitions:
100
+
raise NotImplementedError(f"admonition {kind} not supported yet")
101
+
tag = admonitions[kind]
102
+
# we don't keep whitespace here because usually we'll contain only
103
+
# a single paragraph and the original docbook string is no longer
104
+
# available to restore the trailer.
105
+
return f"<{tag}><para>{text.rstrip()}</para></{tag}>"
106
+
def block_quote(self, text):
107
+
return f"<blockquote><para>{text}</para></blockquote>"
108
+
def command(self, text):
109
+
return f"<command>{escape(text)}</command>"
110
+
def option(self, text):
111
+
return f"<option>{escape(text)}</option>"
112
+
def file(self, text):
113
+
return f"<filename>{escape(text)}</filename>"
114
+
def manpage(self, page, section):
115
+
title = f"<refentrytitle>{escape(page)}</refentrytitle>"
116
+
vol = f"<manvolnum>{escape(section)}</manvolnum>"
117
+
return f"<citerefentry>{title}{vol}</citerefentry>"
119
+
def finalize(self, data):
120
+
return "".join(data)
COMMAND_PATTERN = r'\{command\}`(.*?)`'
129
-
def parse(self, m, state):
130
-
return ('command', m.group(1))
131
-
md.inline.register_rule('command', COMMAND_PATTERN, parse)
132
-
md.inline.rules.append('command')
133
-
plugins.append(command)
124
+
def parse(self, m, state):
125
+
return ('command', m.group(1))
126
+
md.inline.register_rule('command', COMMAND_PATTERN, parse)
127
+
md.inline.rules.append('command')
FILE_PATTERN = r'\{file\}`(.*?)`'
137
-
def parse(self, m, state):
138
-
return ('file', m.group(1))
139
-
md.inline.register_rule('file', FILE_PATTERN, parse)
140
-
md.inline.rules.append('file')
141
-
plugins.append(file)
131
+
def parse(self, m, state):
132
+
return ('file', m.group(1))
133
+
md.inline.register_rule('file', FILE_PATTERN, parse)
134
+
md.inline.rules.append('file')
OPTION_PATTERN = r'\{option\}`(.*?)`'
145
-
def parse(self, m, state):
146
-
return ('option', m.group(1))
147
-
md.inline.register_rule('option', OPTION_PATTERN, parse)
148
-
md.inline.rules.append('option')
149
-
plugins.append(option)
138
+
def parse(self, m, state):
139
+
return ('option', m.group(1))
140
+
md.inline.register_rule('option', OPTION_PATTERN, parse)
141
+
md.inline.rules.append('option')
MANPAGE_PATTERN = r'\{manpage\}`(.*?)\((.+?)\)`'
153
-
def parse(self, m, state):
154
-
return ('manpage', m.group(1), m.group(2))
155
-
md.inline.register_rule('manpage', MANPAGE_PATTERN, parse)
156
-
md.inline.rules.append('manpage')
157
-
plugins.append(manpage)
145
+
def parse(self, m, state):
146
+
return ('manpage', m.group(1), m.group(2))
147
+
md.inline.register_rule('manpage', MANPAGE_PATTERN, parse)
148
+
md.inline.rules.append('manpage')
150
+
def p_admonition(md):
ADMONITION_PATTERN = re.compile(r'^::: \{([^\n]*?)\}\n(.*?)^:::\n', flags=re.MULTILINE|re.DOTALL)
160
-
def admonition(md):
161
-
def parse(self, m, state):
163
-
'type': 'admonition',
164
-
'children': self.parse(m.group(2), state),
165
-
'params': [ m.group(1) ],
167
-
md.block.register_rule('admonition', ADMONITION_PATTERN, parse)
168
-
md.block.rules.append('admonition')
169
-
plugins.append(admonition)
152
+
def parse(self, m, state):
154
+
'type': 'admonition',
155
+
'children': self.parse(m.group(2), state),
156
+
'params': [ m.group(1) ],
158
+
md.block.register_rule('admonition', ADMONITION_PATTERN, parse)
159
+
md.block.rules.append('admonition')
161
+
md = mistune.create_markdown(renderer=Renderer(), plugins=[
162
+
p_command, p_file, p_option, p_manpage, p_admonition
165
+
# converts in-place!
166
+
def convertMD(options: Dict[str, Any]) -> str:
def convertString(path: str, text: str) -> str:
172
-
rendered = mistune.markdown(text, renderer=Renderer(path), plugins=plugins)
173
-
# keep trailing spaces so we can diff the generated XML to check for conversion bugs.
174
-
return rendered.rstrip() + text[len(text.rstrip()):]
169
+
rendered = md(text)
170
+
# keep trailing spaces so we can diff the generated XML to check for conversion bugs.
171
+
return rendered.rstrip() + text[len(text.rstrip()):]
173
+
print(f"error in {path}")
def optionIs(option: Dict[str, Any], key: str, typ: str) -> bool:
if key not in option: return False