Skip to content

Commit 1957426

Browse files
authored
Merge pull request #2027 from gmilde/rst-fixes
Next set of fixes for the reStructuredText import.
2 parents f3e2203 + 4f131b5 commit 1957426

File tree

2 files changed

+102
-23
lines changed

2 files changed

+102
-23
lines changed

src/moin/converters/_tests/test_rst_in.py

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ def setup_class(self):
3737
("**Text**", "<page><body><p><strong>Text</strong></p></body></page>"),
3838
("*Text*", "<page><body><p><emphasis>Text</emphasis></p></body></page>"),
3939
("``Text``", "<page><body><p><code>Text</code></p></body></page>"),
40+
( # custom role using a CSS class
41+
".. role:: orange\n\n:orange:`colourful` text",
42+
'<page><body><p><span xhtml:class="orange">colourful</span> text</p></body></page>',
43+
),
44+
( # special custom roles for <del> and <ins>
45+
".. role:: del\n.. role:: ins\n\n" ":del:`deleted` text :ins:`inserted` text",
46+
"<page><body><p><del>deleted</del> text <ins>inserted</ins> text</p></body></page>",
47+
),
4048
("a _`Link`", '<page><body><p>a <span id="link">Link</span></p></body></page>'),
4149
(
4250
"`Text <javascript:alert('xss')>`_",
@@ -57,9 +65,10 @@ def test_base(self, input, output):
5765
data = [
5866
(
5967
"1. a\n b\n c\n\n2. b\n\n d",
60-
"""<page><body><list item-label-generate="ordered"><list-item><list-item-body><p>a
61-
b
62-
c</p></list-item-body></list-item><list-item><list-item-body><p>b</p><p>d</p></list-item-body></list-item></list></body></page>""",
68+
'<page><body><list item-label-generate="ordered">'
69+
"<list-item><list-item-body><p>a\nb\nc</p></list-item-body></list-item>"
70+
"<list-item><list-item-body><p>b</p><p>d</p></list-item-body></list-item>"
71+
"</list></body></page>",
6372
),
6473
(
6574
"1. a\n2. b\n\nA. c\n\na. A\n\n 1. B\n\n 2. C\n\n",
@@ -73,12 +82,11 @@ def test_base(self, input, output):
7382
"what\n def\n\nhow\n to",
7483
"<page><body><list><list-item><list-item-label>what</list-item-label><list-item-body><p>def</p></list-item-body></list-item><list-item><list-item-label>how</list-item-label><list-item-body><p>to</p></list-item-body></list-item></list></body></page>",
7584
),
76-
# starting an ordered list with a value other than 1 generates an error
85+
# nested in a block-quote and starting with a value other than 1
7786
(
7887
" 3. A\n #. B",
79-
'<page><body><blockquote><list item-label-generate="ordered"><list-item><list-item-body><p>A</p>'
88+
'<page><body><blockquote><list item-label-generate="ordered" list-start="3"><list-item><list-item-body><p>A</p>'
8089
"</list-item-body></list-item><list-item><list-item-body><p>B</p></list-item-body></list-item></list>"
81-
'<admonition type="error"><p>Enumerated list start value not ordinal-1: "3" (ordinal 3)</p></admonition>'
8290
"</blockquote></body></page>",
8391
),
8492
]
@@ -353,19 +361,45 @@ def test_table(self, input, output):
353361
self.do(input, output)
354362

355363
data = [
364+
# bibliographic data (visible meta-data)
356365
(
357366
":Author: Test\n:Version: $Revision: 1.17 $\n:Copyright: c\n:Test: t",
358367
"<page><body><table><table-body><table-row><table-cell><strong>Author:</strong></table-cell><table-cell>Test</table-cell></table-row><table-row><table-cell><strong>Version:</strong></table-cell><table-cell>1.17</table-cell></table-row><table-row><table-cell><strong>Copyright:</strong></table-cell><table-cell>c</table-cell></table-row><table-row><table-cell><strong>Test:</strong></table-cell><table-cell><p>t</p></table-cell></table-row></table-body></table></body></page>",
359368
),
360-
(
361-
"""
362-
.. note::
363-
:name: note-id
364-
365-
An admonition of type "note"
366-
""",
367-
'<page><body><span id="note-id" /><admonition type="note"><p>An admonition of type "note"</p></admonition></body></page>',
368-
),
369+
# admonitions (hint, info, warning, error, ...)
370+
(
371+
".. note::\n" " :name: note-id\n\n" ' An admonition of type "note"',
372+
'<page><body><span id="note-id" /><admonition type="note">'
373+
'<p>An admonition of type "note"</p></admonition></body></page>',
374+
),
375+
# use an attention for a generic admonition
376+
(
377+
".. admonition:: Generic Admonition\n\n" " Be alert!",
378+
'<page><body><admonition type="attention">'
379+
'<strong xhtml:class="title">Generic Admonition</strong>'
380+
"<p>Be alert!</p></admonition></body></page>",
381+
),
382+
# Moin uses admonitions also for system messages
383+
(
384+
"Unbalanced *inline markup.",
385+
'<page><body><p>Unbalanced <span id="problematic-1" /><a xhtml:class="red" xlink:href="#system-message-1">*</a>inline markup.</p>'
386+
'<span id="system-message-1" /><admonition type="caution">'
387+
'<p><strong xhtml:class="title">System Message: WARNING/2</strong> (rST input line 1) '
388+
'<span id="system-message-1" /><a xlink:href="#problematic-1">backlink</a></p>'
389+
"<p>Inline emphasis start-string without end-string.</p>"
390+
"</admonition></body></page>",
391+
),
392+
# TODO: this currently fails because the parsing error is not cleared.
393+
# (
394+
# "Sections must not be nested in body elements.\n\n"
395+
# " not allowed\n"
396+
# " -----------\n",
397+
# "<page><body><p>Sections must not be nested in body elements.</p><blockquote>"
398+
# '<admonition type="error"><p><strong xhtml:class="title">System Message: ERROR/3</strong> (rST input line 4)</p>'
399+
# "<p>Unexpected section title.</p>"
400+
# "<blockcode>not allowed\n-----------</blockcode>"
401+
# "</admonition></blockquote></body></page>"
402+
# )
369403
]
370404

371405
@pytest.mark.parametrize("input,output", data)

src/moin/converters/rst_in.py

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,9 @@ def visit_enumerated_list(self, node):
314314
type = enum_style.get(node["enumtype"], None)
315315
if type:
316316
new_node.set(moin_page.list_style_type, type)
317+
startvalue = node.get("start", 1)
318+
if startvalue > 1:
319+
new_node.set(moin_page.list_start, str(startvalue))
317320
self.open_moin_page_node(new_node, node)
318321

319322
def depart_enumerated_list(self, node):
@@ -434,10 +437,21 @@ def depart_image(self, node):
434437
self.close_moin_page_node()
435438

436439
def visit_inline(self, node):
437-
pass
440+
classes = node["classes"]
441+
moin_node = moin_page.span
442+
attrib = {}
443+
if "ins" in classes:
444+
moin_node = moin_page.ins
445+
classes.remove("ins")
446+
if "del" in classes:
447+
moin_node = moin_page.del_
448+
classes.remove("del")
449+
if classes:
450+
attrib[html.class_] = " ".join(classes)
451+
self.open_moin_page_node(moin_node(attrib=attrib))
438452

439453
def depart_inline(self, node):
440-
pass
454+
self.close_moin_page_node()
441455

442456
def visit_label(self, node):
443457
if self.status[-1] == "footnote":
@@ -529,6 +543,7 @@ def visit_paragraph(self, node):
529543
footnote_node = self.footnotes.get(self.footnote_lable, None)
530544
if footnote_node:
531545
# TODO: `node.astext()` ignores all markup!
546+
# "moin" footnotes support inline markup
532547
footnote_node.append(node.astext())
533548
raise nodes.SkipNode
534549
self.open_moin_page_node(moin_page.p(), node)
@@ -538,10 +553,15 @@ def depart_paragraph(self, node):
538553
self.close_moin_page_node()
539554

540555
def visit_problematic(self, node):
541-
pass
556+
if node.hasattr("refid"):
557+
refuri = f"#{node['refid']}"
558+
attrib = {xlink.href: refuri, html.class_: "red"}
559+
self.open_moin_page_node(moin_page.a(attrib=attrib), node)
560+
else:
561+
self.open_moin_page_node(moin_page.span(attrib={html.class_: "red"}))
542562

543563
def depart_problematic(self, node):
544-
pass
564+
self.close_moin_page_node()
545565

546566
def visit_reference(self, node):
547567
refuri = node.get("refuri", "")
@@ -584,6 +604,7 @@ def visit_reference(self, node):
584604
return
585605

586606
if not allowed_uri_scheme(refuri):
607+
# TODO: prepend "wiki.local" as in "moin_in"?
587608
self.visit_error(node)
588609
return
589610

@@ -678,9 +699,25 @@ def depart_superscript(self, node):
678699
self.close_moin_page_node()
679700

680701
def visit_system_message(self, node):
681-
# we have encountered a parsing error, insert an error message
682-
# TODO: also show error level and line number.
683-
self.visit_admonition(node, "error")
702+
# an element reporting a parsing issue (DEBUG, INFO, WARNING, ERROR, or SEVERE)
703+
# TODO: handle node['backrefs'] to <problematic> element.
704+
if node.get("level", 4) < 3:
705+
self.visit_admonition(node, "caution")
706+
else:
707+
self.visit_admonition(node, "error")
708+
self.open_moin_page_node(moin_page.p())
709+
self.open_moin_page_node(moin_page.strong(attrib={html.class_: "title"}))
710+
title = f"{node['type']}/{node['level']}"
711+
self.current_node.append(f"System Message: {title}")
712+
self.close_moin_page_node() # </strong>
713+
if node.hasattr("line"):
714+
self.current_node.append(f" ({node['source']} line {node['line']}) ")
715+
if node.get("backrefs", []):
716+
backrefuri = f"#{node['backrefs'][0]}"
717+
self.open_moin_page_node(moin_page.a(attrib={xlink.href: backrefuri}), node)
718+
self.current_node.append("backlink")
719+
self.close_moin_page_node() # </a>
720+
self.close_moin_page_node() # </p>
684721

685722
def depart_system_message(self, node):
686723
self.depart_admonition(node)
@@ -823,6 +860,8 @@ class Parser(docutils.parsers.rst.Parser):
823860
Registers a "transform__" for hyperlink references
824861
without matching target__.
825862
863+
Also register the "transforms" that are added by default for a Docutils writer.
864+
826865
__ https://docutils.sourceforge.io/docs/api/transforms.html
827866
__ https://docutils.sourceforge.io/docs/ref/doctree.html#target
828867
"""
@@ -832,7 +871,13 @@ class Parser(docutils.parsers.rst.Parser):
832871

833872
def get_transforms(self):
834873
"""Add WikiReferences to the registered transforms."""
835-
return super().get_transforms() + [WikiReferences]
874+
moin_parser_transforms = [
875+
WikiReferences,
876+
transforms.universal.StripClassesAndElements,
877+
transforms.universal.Messages,
878+
transforms.universal.FilterMessages,
879+
]
880+
return super().get_transforms() + moin_parser_transforms
836881

837882

838883
class WikiReferences(transforms.Transform):

0 commit comments

Comments
 (0)