# HG changeset patch # User Paul Boddie # Date 1534434737 -7200 # Node ID cf512c95f3d43bf788a3b21a1af05e44c8b838fc # Parent 61b098ed85ee93c86fbd968b512cd36ec0c5ae7e# Parent 9ca45adda2abe5bee9e48304f8c9c66c0ee4636e Merged changes from the default branch. diff -r 61b098ed85ee -r cf512c95f3d4 moinformat/parsers/moin.py --- a/moinformat/parsers/moin.py Tue Aug 14 22:36:06 2018 +0200 +++ b/moinformat/parsers/moin.py Thu Aug 16 17:52:17 2018 +0200 @@ -37,11 +37,12 @@ from moinformat.tree.moin import Anchor, Break, Comment, DefItem, DefTerm, \ Directive, FontStyle, Heading, Larger, \ - LineBreak, Link, List, ListItem, Macro, \ - Monospace, Region, Rule, Smaller, \ - Strikethrough, Subscript, Superscript, Table, \ - TableAttr, TableAttrs, TableCell, TableRow, \ - Text, Underline + LineBreak, Link, LinkLabel, LinkParameter, \ + List, ListItem, Macro, Monospace, Region, \ + Rule, Smaller, Strikethrough, Subscript, \ + Superscript, Table, TableAttr, TableAttrs, \ + TableCell, TableRow, Text, Transclusion, \ + Underline join = "".join @@ -546,6 +547,39 @@ def parse_underline(self, region): self.parse_inline(region, Underline, "underline") + # Link formatting handlers. + + def _parse_link(self, region, cls, pattern_names): + target = self.match_group("target") + end = self.match_group("end") + + span = cls([], target) + + # Obtain the extra details. + + if not end: + cls = LinkLabel + + # Introduce a label or parameter for each separated region. + + while True: + param = cls([]) + self.parse_region_details(param, pattern_names) + span.append(param) + + if self.matching_pattern() != "linksep": + break + + cls = LinkParameter + + region.append_inline(span) + + def parse_link(self, region): + self._parse_link(region, Link, self.link_pattern_names) + + def parse_transclusion(self, region): + self._parse_link(region, Transclusion, self.transclusion_pattern_names) + # Complete inline pattern handlers. @@ -558,12 +592,6 @@ def parse_linebreak(self, region): region.append_inline(LineBreak()) - def parse_link(self, region): - target = self.match_group("target") - text = self.match_group("text") - link = Link(text and [Text(text)] or [], target) - region.append_inline(link) - def parse_macro(self, region): name = self.match_group("name") args = self.match_group("args") @@ -698,6 +726,19 @@ "super" : r"\^", # ^ "underline" : r"__", # __ + # Links and transclusions may start inline spans. + + "link" : join((r"\[\[", # [[ + group("target", ".*?"), # ... + choice((r"\|", # | + group("end", r"]]"))))), # ]] + + "transclusion" : join((r"\{\{", # {{ + excl(r"\{"), # not-{ + group("target", ".*?"), # ... + choice((r"\|", # | + group("end", r"}}"))))), # }} + # Complete inline patterns are for markup features that do not support # arbitrary content within them: @@ -707,12 +748,6 @@ "linebreak" : r"\\\\", # \\ - "link" : join((r"\[\[", # [[ - group("target", ".*?"), # target - optional(join((r"\|", # | - group("text", r"\E*?")))), # text-incl-nl (optional) - "]]")), # ]] - "macro" : join(("<<", # << group("name", "\w+?"), # digit-letter... optional(join((r"\(", # ( (optional) @@ -723,11 +758,13 @@ # Ending patterns for inline features: "largerend" : r"\+~", # +~ + "linkend" : r"]]", # ]] "monospaceend" : r"`", # ` "smallerend" : r"-~", # -~ "strikeend" : r"\)--", # )-- "subend" : r",,", # ,, "superend" : r"\^", # ^ + "transclusionend": r"}}", # }} "underlineend" : r"__", # __ # Heading contents: @@ -736,6 +773,10 @@ group("level", "=+"), # =... group("extra", r"\N*\n"))), # ws (optional) nl + # Link/transclusion contents: + + "linksep" : r"\|", # | + # List contents: "deftermend" : join(("::", group("pad", r"\s*?\n"))), # :: @@ -801,12 +842,18 @@ "valign", "width" ] - inline_pattern_names = [ - "anchor", "fontstyle", "larger", "linebreak", "link", "macro", + inline_without_links_pattern_names = [ + "anchor", "fontstyle", "larger", "linebreak", "macro", "monospace", "regionstart", "smaller", "strike", "sub", "super", "underline", ] + inline_pattern_names = inline_without_links_pattern_names + [ + "link", "transclusion"] + + link_pattern_names = inline_without_links_pattern_names + [ + "linkend", "linksep", "transclusion"] + list_pattern_names = [ "listitem", "listitem_alpha", "listitem_dot", "listitem_num", "listitem_roman", @@ -823,6 +870,9 @@ "tableattrs", "tablecell", "tableend" ] + transclusion_pattern_names = inline_without_links_pattern_names + [ + "linksep", "transclusionend"] + # The region pattern names are specifically used by the common parser # functionality. @@ -856,6 +906,8 @@ "largerend" : end_region, "linebreak" : parse_linebreak, "link" : parse_link, + "linkend" : end_region, + "linksep" : end_region, "macro" : parse_macro, "listitemend" : end_region, "listitem" : parse_listitem, @@ -882,6 +934,8 @@ "tablerow" : parse_table_row, "tablecell" : end_region, "tableend" : end_region, + "transclusion" : parse_transclusion, + "transclusionend" : end_region, "underline" : parse_underline, "underlineend" : end_region, "valign" : parse_valign, diff -r 61b098ed85ee -r cf512c95f3d4 moinformat/serialisers/html/moin.py --- a/moinformat/serialisers/html/moin.py Tue Aug 14 22:36:06 2018 +0200 +++ b/moinformat/serialisers/html/moin.py Thu Aug 16 17:52:17 2018 +0200 @@ -100,17 +100,6 @@ def end_larger(self): self.out("") - def start_link(self, target, nodes): - label = None - if self.linker: - target, label = self.linker.translate(target) - self.out('' % escape_attr(target)) - if not nodes: - self.out(escape_text(label or target)) - - def end_link(self): - self.out("") - def start_linktext(self): pass @@ -262,6 +251,41 @@ def linebreak(self): self.out("
") + def _link(self, target, nodes, tag, attr): + label = None + if self.linker: + target, label = self.linker.translate(target) + + self.out('<%s %s="%s"' % (tag, attr, escape_attr(target))) + + if nodes: + for node in nodes[1:]: + self.out(" ") + node.to_string(self) + + self.out(">") + + if nodes: + nodes[0].to_string(self) + else: + self.out(escape_text(label or target)) + + self.out("" % tag) + + def link(self, target, nodes): + self._link(target, nodes, "a", "href") + + def link_label(self, nodes): + for node in nodes: + node.to_string(self) + + def link_parameter(self, key_value): + if len(key_value) == 1: + self.out(key_value[0]) + else: + key, value = key_value + self.out("%s='%s'" % (key, escape_attr(value))) + def rule(self, length): self.out("
" % min(length, 10)) @@ -278,6 +302,9 @@ def text(self, s): self.out(escape_text(s)) + def transclusion(self, target, nodes): + self._link(target, nodes, "img", "src") + serialiser = HTMLSerialiser # vim: tabstop=4 expandtab shiftwidth=4 diff -r 61b098ed85ee -r cf512c95f3d4 moinformat/serialisers/moin/moin.py --- a/moinformat/serialisers/moin/moin.py Tue Aug 14 22:36:06 2018 +0200 +++ b/moinformat/serialisers/moin/moin.py Thu Aug 16 17:52:17 2018 +0200 @@ -78,18 +78,6 @@ def end_larger(self): self.out("+~") - def start_link(self, target, nodes): - self.out("[[%s" % target) - - def end_link(self): - self.out("]]") - - def start_linktext(self): - self.out("|") - - def end_linktext(self): - pass - def start_list(self, indent, marker, num): pass @@ -194,6 +182,23 @@ def linebreak(self): self.out(r"\\") + def link(self, target, nodes): + self.out("[[%s" % target) + for node in nodes: + self.out("|") + node.to_string(self) + self.out("]]") + + def link_label(self, nodes): + for node in nodes: + node.to_string(self) + + def link_parameter(self, key_value): + if len(key_value) == 1: + self.out(key_value[0]) + else: + self.out("=".join(key_value)) + def rule(self, length): self.out("-" * length) @@ -216,6 +221,13 @@ def text(self, s): self.out(s) + def transclusion(self, target, nodes): + self.out("{{%s" % target) + for node in nodes: + self.out("|") + node.to_string(self) + self.out("}}") + serialiser = MoinSerialiser # vim: tabstop=4 expandtab shiftwidth=4 diff -r 61b098ed85ee -r cf512c95f3d4 moinformat/tree/moin.py --- a/moinformat/tree/moin.py Tue Aug 14 22:36:06 2018 +0200 +++ b/moinformat/tree/moin.py Thu Aug 16 17:52:17 2018 +0200 @@ -370,6 +370,36 @@ self._to_string(out) out.end_heading(self.level, self.end_pad, self.end_extra) +class LinkLabel(Container): + + "A link or transclusion label." + + def __repr__(self): + return "LinkLabel(%r)" % self.nodes + + def prettyprint(self, indent=""): + l = ["%sLinkLabel" % indent] + return self._prettyprint(l, indent) + + def to_string(self, out): + out.link_label(self.nodes) + +class LinkParameter(Container): + + "A link or transclusion parameter." + + def __repr__(self): + return "LinkParameter(%r)" % self.nodes + + def prettyprint(self, indent=""): + l = ["%sLinkParameter" % indent] + return self._prettyprint(l, indent) + + def to_string(self, out): + s = self.text_content() + t = s.split("=", 1) + out.link_parameter(t) + class List(Container): "A list." @@ -531,12 +561,7 @@ return self._prettyprint(l, indent) def to_string(self, out): - out.start_link(self.target, self.nodes) - if self.nodes: - out.start_linktext() - self._to_string(out) - out.end_linktext() - out.end_link() + out.link(self.target, self.nodes) class Macro(Container): @@ -607,6 +632,24 @@ self._to_string(out) out.end_superscript() +class Transclusion(Container): + + "Transclusion details." + + def __init__(self, nodes, target): + Container.__init__(self, nodes) + self.target = target + + def __repr__(self): + return "Transclusion(%r, %r)" % (self.nodes, self.target) + + def prettyprint(self, indent=""): + l = ["%sTransclusion: target=%r" % (indent, self.target)] + return self._prettyprint(l, indent) + + def to_string(self, out): + out.transclusion(self.target, self.nodes) + class Underline(Inline): "Underlined text." diff -r 61b098ed85ee -r cf512c95f3d4 tests/test_anchors.tree --- a/tests/test_anchors.tree Tue Aug 14 22:36:06 2018 +0200 +++ b/tests/test_anchors.tree Thu Aug 16 17:52:17 2018 +0200 @@ -25,7 +25,8 @@ Block Text Link - Text + LinkLabel + Text Text Break Block diff -r 61b098ed85ee -r cf512c95f3d4 tests/test_continuation.tree --- a/tests/test_continuation.tree Tue Aug 14 22:36:06 2018 +0200 +++ b/tests/test_continuation.tree Thu Aug 16 17:52:17 2018 +0200 @@ -17,11 +17,13 @@ TableCell Text Link - Text + LinkLabel + Text Text Continuation Text Link - Text + LinkLabel + Text Text Block diff -r 61b098ed85ee -r cf512c95f3d4 tests/test_links.tree --- a/tests/test_links.tree Tue Aug 14 22:36:06 2018 +0200 +++ b/tests/test_links.tree Thu Aug 16 17:52:17 2018 +0200 @@ -2,26 +2,60 @@ Block Text Link - Text + LinkLabel + Text + Text + Link + LinkLabel + Text + Text + Link + LinkLabel + Text Text Link - Text + LinkLabel + Text Text Link - Text + LinkLabel + Text Text Link - Text + LinkLabel + Text + Text + Link + LinkLabel + Text Text Link - Text + LinkLabel + Text + Text + Break + Block Text Link - Text + LinkLabel + FontStyle + Text + Text Text Link - Text + LinkLabel + Text + LinkParameter + Text + LinkParameter + Text Text - Link - Text + Break + Block Text + Transclusion + LinkLabel + Text + LinkParameter + Text + Text diff -r 61b098ed85ee -r cf512c95f3d4 tests/test_links.txt --- a/tests/test_links.txt Tue Aug 14 22:36:06 2018 +0200 +++ b/tests/test_links.txt Thu Aug 16 17:52:17 2018 +0200 @@ -2,3 +2,7 @@ [[../Sibling|sibling]], [[../../ParentSibling|sibling of parent]], [[http://www.python.org/|URL]], [[attachment:image.png|attachment]], [[MoinMoin:RecentChanges|interwiki]]. + +A [[SomePage|''fancy'' link]] and [[SomePage|another|with|arguments]]. + +An {{attachment:picture.jpg|image|width=200}}.