1.1 --- a/moinformat/parsers/moin.py Tue Aug 14 22:33:30 2018 +0200
1.2 +++ b/moinformat/parsers/moin.py Thu Aug 16 17:51:57 2018 +0200
1.3 @@ -37,11 +37,12 @@
1.4
1.5 from moinformat.tree.moin import Anchor, Break, Comment, DefItem, DefTerm, \
1.6 Directive, FontStyle, Heading, Larger, \
1.7 - LineBreak, Link, List, ListItem, Macro, \
1.8 - Monospace, Region, Rule, Smaller, \
1.9 - Strikethrough, Subscript, Superscript, Table, \
1.10 - TableAttr, TableAttrs, TableCell, TableRow, \
1.11 - Text, Underline
1.12 + LineBreak, Link, LinkLabel, LinkParameter, \
1.13 + List, ListItem, Macro, Monospace, Region, \
1.14 + Rule, Smaller, Strikethrough, Subscript, \
1.15 + Superscript, Table, TableAttr, TableAttrs, \
1.16 + TableCell, TableRow, Text, Transclusion, \
1.17 + Underline
1.18
1.19 join = "".join
1.20
1.21 @@ -546,6 +547,39 @@
1.22 def parse_underline(self, region):
1.23 self.parse_inline(region, Underline, "underline")
1.24
1.25 + # Link formatting handlers.
1.26 +
1.27 + def _parse_link(self, region, cls, pattern_names):
1.28 + target = self.match_group("target")
1.29 + end = self.match_group("end")
1.30 +
1.31 + span = cls([], target)
1.32 +
1.33 + # Obtain the extra details.
1.34 +
1.35 + if not end:
1.36 + cls = LinkLabel
1.37 +
1.38 + # Introduce a label or parameter for each separated region.
1.39 +
1.40 + while True:
1.41 + param = cls([])
1.42 + self.parse_region_details(param, pattern_names)
1.43 + span.append(param)
1.44 +
1.45 + if self.matching_pattern() != "linksep":
1.46 + break
1.47 +
1.48 + cls = LinkParameter
1.49 +
1.50 + region.append_inline(span)
1.51 +
1.52 + def parse_link(self, region):
1.53 + self._parse_link(region, Link, self.link_pattern_names)
1.54 +
1.55 + def parse_transclusion(self, region):
1.56 + self._parse_link(region, Transclusion, self.transclusion_pattern_names)
1.57 +
1.58
1.59
1.60 # Complete inline pattern handlers.
1.61 @@ -558,12 +592,6 @@
1.62 def parse_linebreak(self, region):
1.63 region.append_inline(LineBreak())
1.64
1.65 - def parse_link(self, region):
1.66 - target = self.match_group("target")
1.67 - text = self.match_group("text")
1.68 - link = Link(text and [Text(text)] or [], target)
1.69 - region.append_inline(link)
1.70 -
1.71 def parse_macro(self, region):
1.72 name = self.match_group("name")
1.73 args = self.match_group("args")
1.74 @@ -698,6 +726,19 @@
1.75 "super" : r"\^", # ^
1.76 "underline" : r"__", # __
1.77
1.78 + # Links and transclusions may start inline spans.
1.79 +
1.80 + "link" : join((r"\[\[", # [[
1.81 + group("target", ".*?"), # ...
1.82 + choice((r"\|", # |
1.83 + group("end", r"]]"))))), # ]]
1.84 +
1.85 + "transclusion" : join((r"\{\{", # {{
1.86 + excl(r"\{"), # not-{
1.87 + group("target", ".*?"), # ...
1.88 + choice((r"\|", # |
1.89 + group("end", r"}}"))))), # }}
1.90 +
1.91 # Complete inline patterns are for markup features that do not support
1.92 # arbitrary content within them:
1.93
1.94 @@ -707,12 +748,6 @@
1.95
1.96 "linebreak" : r"\\\\", # \\
1.97
1.98 - "link" : join((r"\[\[", # [[
1.99 - group("target", ".*?"), # target
1.100 - optional(join((r"\|", # |
1.101 - group("text", r"\E*?")))), # text-incl-nl (optional)
1.102 - "]]")), # ]]
1.103 -
1.104 "macro" : join(("<<", # <<
1.105 group("name", "\w+?"), # digit-letter...
1.106 optional(join((r"\(", # ( (optional)
1.107 @@ -723,11 +758,13 @@
1.108 # Ending patterns for inline features:
1.109
1.110 "largerend" : r"\+~", # +~
1.111 + "linkend" : r"]]", # ]]
1.112 "monospaceend" : r"`", # `
1.113 "smallerend" : r"-~", # -~
1.114 "strikeend" : r"\)--", # )--
1.115 "subend" : r",,", # ,,
1.116 "superend" : r"\^", # ^
1.117 + "transclusionend": r"}}", # }}
1.118 "underlineend" : r"__", # __
1.119
1.120 # Heading contents:
1.121 @@ -736,6 +773,10 @@
1.122 group("level", "=+"), # =...
1.123 group("extra", r"\N*\n"))), # ws (optional) nl
1.124
1.125 + # Link/transclusion contents:
1.126 +
1.127 + "linksep" : r"\|", # |
1.128 +
1.129 # List contents:
1.130
1.131 "deftermend" : join(("::", group("pad", r"\s*?\n"))), # ::
1.132 @@ -801,12 +842,18 @@
1.133 "valign", "width"
1.134 ]
1.135
1.136 - inline_pattern_names = [
1.137 - "anchor", "fontstyle", "larger", "linebreak", "link", "macro",
1.138 + inline_without_links_pattern_names = [
1.139 + "anchor", "fontstyle", "larger", "linebreak", "macro",
1.140 "monospace", "regionstart", "smaller", "strike", "sub", "super",
1.141 "underline",
1.142 ]
1.143
1.144 + inline_pattern_names = inline_without_links_pattern_names + [
1.145 + "link", "transclusion"]
1.146 +
1.147 + link_pattern_names = inline_without_links_pattern_names + [
1.148 + "linkend", "linksep", "transclusion"]
1.149 +
1.150 list_pattern_names = [
1.151 "listitem", "listitem_alpha", "listitem_dot", "listitem_num",
1.152 "listitem_roman",
1.153 @@ -823,6 +870,9 @@
1.154 "tableattrs", "tablecell", "tableend"
1.155 ]
1.156
1.157 + transclusion_pattern_names = inline_without_links_pattern_names + [
1.158 + "linksep", "transclusionend"]
1.159 +
1.160 # The region pattern names are specifically used by the common parser
1.161 # functionality.
1.162
1.163 @@ -856,6 +906,8 @@
1.164 "largerend" : end_region,
1.165 "linebreak" : parse_linebreak,
1.166 "link" : parse_link,
1.167 + "linkend" : end_region,
1.168 + "linksep" : end_region,
1.169 "macro" : parse_macro,
1.170 "listitemend" : end_region,
1.171 "listitem" : parse_listitem,
1.172 @@ -882,6 +934,8 @@
1.173 "tablerow" : parse_table_row,
1.174 "tablecell" : end_region,
1.175 "tableend" : end_region,
1.176 + "transclusion" : parse_transclusion,
1.177 + "transclusionend" : end_region,
1.178 "underline" : parse_underline,
1.179 "underlineend" : end_region,
1.180 "valign" : parse_valign,
2.1 --- a/moinformat/serialisers/html/moin.py Tue Aug 14 22:33:30 2018 +0200
2.2 +++ b/moinformat/serialisers/html/moin.py Thu Aug 16 17:51:57 2018 +0200
2.3 @@ -100,17 +100,6 @@
2.4 def end_larger(self):
2.5 self.out("</big>")
2.6
2.7 - def start_link(self, target, nodes):
2.8 - label = None
2.9 - if self.linker:
2.10 - target, label = self.linker.translate(target)
2.11 - self.out('<a href="%s">' % escape_attr(target))
2.12 - if not nodes:
2.13 - self.out(escape_text(label or target))
2.14 -
2.15 - def end_link(self):
2.16 - self.out("</a>")
2.17 -
2.18 def start_linktext(self):
2.19 pass
2.20
2.21 @@ -262,6 +251,41 @@
2.22 def linebreak(self):
2.23 self.out("<br />")
2.24
2.25 + def _link(self, target, nodes, tag, attr):
2.26 + label = None
2.27 + if self.linker:
2.28 + target, label = self.linker.translate(target)
2.29 +
2.30 + self.out('<%s %s="%s"' % (tag, attr, escape_attr(target)))
2.31 +
2.32 + if nodes:
2.33 + for node in nodes[1:]:
2.34 + self.out(" ")
2.35 + node.to_string(self)
2.36 +
2.37 + self.out(">")
2.38 +
2.39 + if nodes:
2.40 + nodes[0].to_string(self)
2.41 + else:
2.42 + self.out(escape_text(label or target))
2.43 +
2.44 + self.out("</%s>" % tag)
2.45 +
2.46 + def link(self, target, nodes):
2.47 + self._link(target, nodes, "a", "href")
2.48 +
2.49 + def link_label(self, nodes):
2.50 + for node in nodes:
2.51 + node.to_string(self)
2.52 +
2.53 + def link_parameter(self, key_value):
2.54 + if len(key_value) == 1:
2.55 + self.out(key_value[0])
2.56 + else:
2.57 + key, value = key_value
2.58 + self.out("%s='%s'" % (key, escape_attr(value)))
2.59 +
2.60 def rule(self, length):
2.61 self.out("<hr style='height: %dpt' />" % min(length, 10))
2.62
2.63 @@ -278,6 +302,9 @@
2.64 def text(self, s):
2.65 self.out(escape_text(s))
2.66
2.67 + def transclusion(self, target, nodes):
2.68 + self._link(target, nodes, "img", "src")
2.69 +
2.70 serialiser = HTMLSerialiser
2.71
2.72 # vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/moinformat/tree/moin.py Tue Aug 14 22:33:30 2018 +0200
4.2 +++ b/moinformat/tree/moin.py Thu Aug 16 17:51:57 2018 +0200
4.3 @@ -370,6 +370,36 @@
4.4 self._to_string(out)
4.5 out.end_heading(self.level, self.end_pad, self.end_extra)
4.6
4.7 +class LinkLabel(Container):
4.8 +
4.9 + "A link or transclusion label."
4.10 +
4.11 + def __repr__(self):
4.12 + return "LinkLabel(%r)" % self.nodes
4.13 +
4.14 + def prettyprint(self, indent=""):
4.15 + l = ["%sLinkLabel" % indent]
4.16 + return self._prettyprint(l, indent)
4.17 +
4.18 + def to_string(self, out):
4.19 + out.link_label(self.nodes)
4.20 +
4.21 +class LinkParameter(Container):
4.22 +
4.23 + "A link or transclusion parameter."
4.24 +
4.25 + def __repr__(self):
4.26 + return "LinkParameter(%r)" % self.nodes
4.27 +
4.28 + def prettyprint(self, indent=""):
4.29 + l = ["%sLinkParameter" % indent]
4.30 + return self._prettyprint(l, indent)
4.31 +
4.32 + def to_string(self, out):
4.33 + s = self.text_content()
4.34 + t = s.split("=", 1)
4.35 + out.link_parameter(t)
4.36 +
4.37 class List(Container):
4.38
4.39 "A list."
4.40 @@ -531,12 +561,7 @@
4.41 return self._prettyprint(l, indent)
4.42
4.43 def to_string(self, out):
4.44 - out.start_link(self.target, self.nodes)
4.45 - if self.nodes:
4.46 - out.start_linktext()
4.47 - self._to_string(out)
4.48 - out.end_linktext()
4.49 - out.end_link()
4.50 + out.link(self.target, self.nodes)
4.51
4.52 class Macro(Container):
4.53
4.54 @@ -607,6 +632,24 @@
4.55 self._to_string(out)
4.56 out.end_superscript()
4.57
4.58 +class Transclusion(Container):
4.59 +
4.60 + "Transclusion details."
4.61 +
4.62 + def __init__(self, nodes, target):
4.63 + Container.__init__(self, nodes)
4.64 + self.target = target
4.65 +
4.66 + def __repr__(self):
4.67 + return "Transclusion(%r, %r)" % (self.nodes, self.target)
4.68 +
4.69 + def prettyprint(self, indent=""):
4.70 + l = ["%sTransclusion: target=%r" % (indent, self.target)]
4.71 + return self._prettyprint(l, indent)
4.72 +
4.73 + def to_string(self, out):
4.74 + out.transclusion(self.target, self.nodes)
4.75 +
4.76 class Underline(Inline):
4.77
4.78 "Underlined text."