1.1 --- a/moinformat/serialisers/__init__.py Tue Jun 20 18:58:47 2023 +0200
1.2 +++ b/moinformat/serialisers/__init__.py Wed Jun 28 16:12:26 2023 +0200
1.3 @@ -3,7 +3,7 @@
1.4 """
1.5 Moin wiki serialisers.
1.6
1.7 -Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
1.8 +Copyright (C) 2017, 2018, 2023 Paul Boddie <paul@boddie.org.uk>
1.9
1.10 This program is free software; you can redistribute it and/or modify it under
1.11 the terms of the GNU General Public License as published by the Free Software
1.12 @@ -43,7 +43,7 @@
1.13 "Serialise 'doc' using the given 'serialiser' instance."
1.14
1.15 serialiser.reset()
1.16 - doc.to_string(serialiser)
1.17 + doc.visit(serialiser)
1.18 return serialiser.get_output()
1.19
1.20 # vim: tabstop=4 expandtab shiftwidth=4
2.1 --- a/moinformat/serialisers/common.py Tue Jun 20 18:58:47 2023 +0200
2.2 +++ b/moinformat/serialisers/common.py Wed Jun 28 16:12:26 2023 +0200
2.3 @@ -3,7 +3,7 @@
2.4 """
2.5 Moin serialiser support.
2.6
2.7 -Copyright (C) 2017, 2018, 2019, 2021 Paul Boddie <paul@boddie.org.uk>
2.8 +Copyright (C) 2017, 2018, 2019, 2021, 2023 Paul Boddie <paul@boddie.org.uk>
2.9
2.10 This program is free software; you can redistribute it and/or modify it under
2.11 the terms of the GNU General Public License as published by the Free Software
2.12 @@ -92,6 +92,36 @@
2.13 else:
2.14 return cls(self.metadata, self.serialisers)
2.15
2.16 + # Serialisation visitor methods.
2.17 +
2.18 + def to_string(self, node):
2.19 +
2.20 + "Visit the 'node' to invoke the appropriate serialisation handler."
2.21 +
2.22 + node.visit(self)
2.23 +
2.24 + def region_to_string(self, region):
2.25 +
2.26 + """
2.27 + Obtain a serialiser for the region from the same format family. Retain
2.28 + the same serialiser if no appropriate serialiser could be obtained.
2.29 + """
2.30 +
2.31 + serialiser_name = self.formats and "%s.%s" % (self.formats[0], region.type) or None
2.32 + serialiser = self.get_serialiser(serialiser_name)
2.33 +
2.34 + # Serialise the region.
2.35 +
2.36 + serialiser.container(region)
2.37 +
2.38 + def container(self, container):
2.39 +
2.40 + "Visit all nodes in 'container'."
2.41 +
2.42 + if container.nodes:
2.43 + for node in container.nodes:
2.44 + self.to_string(node)
2.45 +
2.46 def escape_attr(s):
2.47
2.48 "Escape XML document attribute."
3.1 --- a/moinformat/serialisers/html/graphviz.py Tue Jun 20 18:58:47 2023 +0200
3.2 +++ b/moinformat/serialisers/html/graphviz.py Wed Jun 28 16:12:26 2023 +0200
3.3 @@ -3,7 +3,7 @@
3.4 """
3.5 Graphviz serialiser, generating content for embedding in HTML documents.
3.6
3.7 -Copyright (C) 2018, 2019, 2022 Paul Boddie <paul@boddie.org.uk>
3.8 +Copyright (C) 2018, 2019, 2022, 2023 Paul Boddie <paul@boddie.org.uk>
3.9
3.10 This program is free software; you can redistribute it and/or modify it under
3.11 the terms of the GNU General Public License as published by the Free Software
3.12 @@ -61,13 +61,13 @@
3.13 def end_block(self):
3.14 pass
3.15
3.16 - def directive(self, key, value, directive):
3.17 - if not self.directives.has_key(key):
3.18 - self.directives[key] = []
3.19 - self.directives[key].append(value)
3.20 + def directive(self, directive):
3.21 + if not self.directives.has_key(directive.key):
3.22 + self.directives[directive.key] = []
3.23 + self.directives[directive.key].append(directive.value)
3.24
3.25 def text(self, text):
3.26 - self.process_graph(text)
3.27 + self.process_graph(text.s)
3.28
3.29
3.30
4.1 --- a/moinformat/serialisers/html/moin.py Tue Jun 20 18:58:47 2023 +0200
4.2 +++ b/moinformat/serialisers/html/moin.py Wed Jun 28 16:12:26 2023 +0200
4.3 @@ -3,7 +3,8 @@
4.4 """
4.5 HTML serialiser.
4.6
4.7 -Copyright (C) 2017, 2018, 2019, 2021, 2022 Paul Boddie <paul@boddie.org.uk>
4.8 +Copyright (C) 2017, 2018, 2019, 2021, 2022,
4.9 + 2023 Paul Boddie <paul@boddie.org.uk>
4.10
4.11 This program is free software; you can redistribute it and/or modify it under
4.12 the terms of the GNU General Public License as published by the Free Software
4.13 @@ -30,90 +31,7 @@
4.14 input_formats = ["moin", "wiki"]
4.15 formats = ["html"]
4.16
4.17 - def _region_tag(self, type):
4.18 -
4.19 - # NOTE: Need to support types in general.
4.20 -
4.21 - type = type and type.split()[0]
4.22 -
4.23 - if type == "inline":
4.24 - return "tt"
4.25 - elif type in (None, "python"):
4.26 - return "pre"
4.27 - else:
4.28 - return "span"
4.29 -
4.30 - def start_region(self, level, indent, type, args, extra):
4.31 -
4.32 - # Generate attributes, joining them when preparing the tag.
4.33 -
4.34 - l = []
4.35 - out = l.append
4.36 -
4.37 - if level:
4.38 - out("level-%d" % level)
4.39 -
4.40 - if indent:
4.41 - out("indent-%d" % indent)
4.42 -
4.43 - # NOTE: Encode type details for CSS.
4.44 -
4.45 - out("type-%s" % escape_attr(type or "opaque"))
4.46 -
4.47 - tag = self._region_tag(type)
4.48 -
4.49 - # Inline regions must preserve "indent" as space in the text.
4.50 -
4.51 - if type == "inline" and indent:
4.52 - self.out(" " * indent)
4.53 -
4.54 - self.out("<%s class='%s'>" % (tag, " ".join(l)))
4.55 -
4.56 - def end_region(self, level, indent, type, args, extra):
4.57 - tag = self._region_tag(type)
4.58 - self.out("</%s>" % tag)
4.59 -
4.60 - def start_block(self):
4.61 - self.out("<p>")
4.62 -
4.63 - def end_block(self):
4.64 - self.out("</p>")
4.65 -
4.66 - def start_defitem(self, pad, extra):
4.67 - self.out("<dd>")
4.68 -
4.69 - def end_defitem(self, pad, extra):
4.70 - self.out("</dd>")
4.71 -
4.72 - def start_defterm(self, pad, extra):
4.73 - self.out("<dt>")
4.74 -
4.75 - def end_defterm(self, pad, extra):
4.76 - self.out("</dt>")
4.77 -
4.78 - def start_emphasis(self):
4.79 - self.out("<em>")
4.80 -
4.81 - def end_emphasis(self):
4.82 - self.out("</em>")
4.83 -
4.84 - def start_heading(self, level, extra, pad, identifier):
4.85 - self.out("<h%d id='%s'>" % (level, escape_attr(self.linker.make_id(identifier))))
4.86 -
4.87 - def end_heading(self, level, pad, extra):
4.88 - self.out("</h%d>" % level)
4.89 -
4.90 - def start_larger(self):
4.91 - self.out("<big>")
4.92 -
4.93 - def end_larger(self):
4.94 - self.out("</big>")
4.95 -
4.96 - def start_linktext(self):
4.97 - pass
4.98 -
4.99 - def end_linktext(self):
4.100 - pass
4.101 + # Support methods.
4.102
4.103 list_tags = {
4.104 "i" : "lower-roman",
4.105 @@ -132,141 +50,246 @@
4.106
4.107 return "ul", None
4.108
4.109 - def start_list(self, indent, marker, num):
4.110 - tag, style_type = self._get_list_tag(marker)
4.111 - style = style_type and ' style="list-style-type: %s"' % escape_attr(style_type) or ""
4.112 - start = style_type and num is not None and ' start="%s"' % escape_attr(num) or ""
4.113 - self.out("<%s%s%s>" % (tag, style, start))
4.114 + def _link(self, target, nodes, tag, attr):
4.115 + link = self.linker and self.linker.translate(target) or None
4.116 +
4.117 + self.out('<%s %s="%s"' % (tag, attr, escape_attr(link.get_target())))
4.118 +
4.119 + # Provide link parameters as attributes.
4.120 +
4.121 + if nodes:
4.122 + for node in nodes:
4.123 + if isinstance(node, LinkParameter):
4.124 + self.out(" ")
4.125 + node.visit(self)
4.126 +
4.127 + # Close the tag if an image.
4.128 +
4.129 + if tag == "img":
4.130 + self.out(" />")
4.131 +
4.132 + # Provide the link label if specified. Otherwise, use a generated
4.133 + # default for the label.
4.134 +
4.135 + else:
4.136 + self.out(">")
4.137 +
4.138 + for node in nodes or []:
4.139 + if isinstance(node, LinkLabel):
4.140 + node.visit(self)
4.141 + break
4.142 + else:
4.143 + self.out(escape_text(link.get_label()))
4.144 +
4.145 + self.out("</%s>" % tag)
4.146 +
4.147 + def _region_tag(self, type):
4.148 +
4.149 + # NOTE: Need to support types in general.
4.150 +
4.151 + type = type and type.split()[0]
4.152
4.153 - def end_list(self, indent, marker, num):
4.154 - tag, style = self._get_list_tag(marker)
4.155 + if type == "inline":
4.156 + return "tt"
4.157 + elif type in (None, "python"):
4.158 + return "pre"
4.159 + else:
4.160 + return "span"
4.161 +
4.162 + # Node handler methods.
4.163 +
4.164 + def region(self, region):
4.165 + tag = self._region_tag(region.type)
4.166 +
4.167 + # Generate attributes, joining them when preparing the tag.
4.168 +
4.169 + attrs = []
4.170 + attr = attrs.append
4.171 +
4.172 + if region.level:
4.173 + attr("level-%d" % region.level)
4.174 +
4.175 + if region.indent:
4.176 + attr("indent-%d" % region.indent)
4.177 +
4.178 + # NOTE: Encode type details for CSS.
4.179 +
4.180 + attr("type-%s" % escape_attr(region.type or "opaque"))
4.181 +
4.182 + # Inline regions must preserve "indent" as space in the text.
4.183 +
4.184 + if region.type == "inline" and region.indent:
4.185 + self.out(" " * region.indent)
4.186 +
4.187 + self.out("<%s class='%s'>" % (tag, " ".join(attrs)))
4.188 +
4.189 + # Serialise the region content.
4.190 +
4.191 + self.region_to_string(region)
4.192 +
4.193 + # End the region with the previous serialiser.
4.194 +
4.195 self.out("</%s>" % tag)
4.196
4.197 - def start_listitem(self, indent, marker, space, num):
4.198 + # Block node methods.
4.199 +
4.200 + def block(self, block):
4.201 + self.out("<p>")
4.202 + self.container(block)
4.203 + self.out("</p>")
4.204 +
4.205 + def defitem(self, defitem):
4.206 + self.out("<dd>")
4.207 + self.container(defitem)
4.208 + self.out("</dd>")
4.209 +
4.210 + def defterm(self, defterm):
4.211 + self.out("<dt>")
4.212 + self.container(defterm)
4.213 + self.out("</dt>")
4.214 +
4.215 + def fontstyle(self, fontstyle):
4.216 + if fontstyle.emphasis:
4.217 + self.out("<em>")
4.218 + elif fontstyle.strong:
4.219 + self.out("<strong>")
4.220 + self.container(fontstyle)
4.221 + if fontstyle.emphasis:
4.222 + self.out("</em>")
4.223 + elif fontstyle.strong:
4.224 + self.out("</strong>")
4.225 +
4.226 + def heading(self, heading):
4.227 + self.out("<h%d id='%s'>" % (
4.228 + heading.level,
4.229 + escape_attr(self.linker.make_id(heading.identifier))))
4.230 + self.container(heading)
4.231 + self.out("</h%d>" % heading.level)
4.232 +
4.233 + def larger(self, larger):
4.234 + self.out("<big>")
4.235 + self.container(larger)
4.236 + self.out("</big>")
4.237 +
4.238 + def list(self, list):
4.239 + tag, style_type = self._get_list_tag(list.marker)
4.240 + style = style_type and \
4.241 + ' style="list-style-type: %s"' % escape_attr(style_type) or ""
4.242 + start = style_type and \
4.243 + list.num is not None and ' start="%s"' % escape_attr(list.num) or ""
4.244 + self.out("<%s%s%s>" % (tag, style, start))
4.245 + self.container(list)
4.246 + self.out("</%s>" % tag)
4.247 +
4.248 + def listitem(self, listitem):
4.249 self.out("<li>")
4.250 -
4.251 - def end_listitem(self, indent, marker, space, num):
4.252 + self.container(listitem)
4.253 self.out("</li>")
4.254
4.255 - def start_macro(self, name, args, nodes, inline):
4.256 + def macro(self, macro):
4.257
4.258 # Special case of a deliberately unexpanded macro.
4.259
4.260 - if nodes is None:
4.261 + if macro.nodes is None:
4.262 return
4.263
4.264 - tag = inline and "span" or "div"
4.265 - self.out("<%s class='macro %s'>" % (tag, escape_text(name)))
4.266 + tag = macro.inline and "span" or "div"
4.267 + self.out("<%s class='macro %s'>" % (tag, escape_text(macro.name)))
4.268
4.269 # Fallback case for when macros are not replaced.
4.270
4.271 - if not nodes:
4.272 + if not macro.nodes:
4.273 self.out(escape_text("<<"))
4.274 - self.out("<span class='name'>%s</span>" % escape_text(name))
4.275 - if args:
4.276 + self.out("<span class='name'>%s</span>" % escape_text(macro.name))
4.277 + if macro.args:
4.278 self.out("(")
4.279 first = True
4.280 - for arg in args:
4.281 + for arg in macro.args:
4.282 if not first:
4.283 self.out(",")
4.284 self.out("<span class='arg'>%s</span>" % escape_text(arg))
4.285 first = False
4.286 - if args:
4.287 + if macro.args:
4.288 self.out(")")
4.289 self.out(escape_text(">>"))
4.290
4.291 - def end_macro(self, inline):
4.292 - tag = inline and "span" or "div"
4.293 + # Produce the expanded macro content.
4.294 +
4.295 + else:
4.296 + self.container(macro)
4.297 +
4.298 + tag = macro.inline and "span" or "div"
4.299 self.out("</%s>" % tag)
4.300
4.301 - def start_monospace(self):
4.302 + def monospace(self, monospace):
4.303 self.out("<tt>")
4.304 -
4.305 - def end_monospace(self):
4.306 + self.container(monospace)
4.307 self.out("</tt>")
4.308
4.309 - def start_smaller(self):
4.310 + def smaller(self, smaller):
4.311 self.out("<small>")
4.312 -
4.313 - def end_smaller(self):
4.314 + self.container(smaller)
4.315 self.out("</small>")
4.316
4.317 - def start_strikethrough(self):
4.318 + def strikethrough(self, strikethrough):
4.319 self.out("<del>")
4.320 -
4.321 - def end_strikethrough(self):
4.322 + self.container(strikethrough)
4.323 self.out("</del>")
4.324
4.325 - def start_strong(self):
4.326 - self.out("<strong>")
4.327 -
4.328 - def end_strong(self):
4.329 - self.out("</strong>")
4.330 -
4.331 - def start_subscript(self):
4.332 + def subscript(self):
4.333 self.out("<sub>")
4.334 -
4.335 - def end_subscript(self):
4.336 + self.container(subscript)
4.337 self.out("</sub>")
4.338
4.339 - def start_superscript(self):
4.340 + def superscript(self, superscript):
4.341 self.out("<sup>")
4.342 -
4.343 - def end_superscript(self):
4.344 + self.container(superscript)
4.345 self.out("</sup>")
4.346
4.347 - def start_table(self):
4.348 + def table(self, table):
4.349 self.out("<table>")
4.350 -
4.351 - def end_table(self):
4.352 + self.container(table)
4.353 self.out("</table>")
4.354
4.355 - def start_table_attrs(self):
4.356 - pass
4.357 -
4.358 - def end_table_attrs(self):
4.359 - pass
4.360 -
4.361 - def start_table_cell(self, attrs, leading, padding):
4.362 + def table_cell(self, table_cell):
4.363 self.out("<td")
4.364
4.365 # Handle the attributes separately from their container.
4.366
4.367 - if attrs and not attrs.empty():
4.368 - for attr in attrs.nodes:
4.369 - attr.to_string(self)
4.370 + if table_cell.attrs and not table_cell.attrs.empty():
4.371 + for attr in table_cell.attrs.nodes:
4.372 + attr.visit(self)
4.373
4.374 self.out(">")
4.375 -
4.376 - def end_table_cell(self):
4.377 + self.container(table_cell)
4.378 self.out("</td>")
4.379
4.380 - def start_table_row(self, leading, padding):
4.381 + def table_row(self, table_row):
4.382 self.out("<tr>")
4.383 -
4.384 - def end_table_row(self, trailing):
4.385 + self.container(table_row)
4.386 self.out("</tr>")
4.387
4.388 - def start_underline(self):
4.389 + def underline(self, underline):
4.390 self.out("<span style='text-decoration: underline'>")
4.391 -
4.392 - def end_underline(self):
4.393 + self.container(underline)
4.394 self.out("</span>")
4.395
4.396 - def anchor(self, target):
4.397 - self.out("<a name='%s' />" % escape_attr(self.linker.make_id(target)))
4.398 + # Inline node methods.
4.399
4.400 - def break_(self):
4.401 + def anchor(self, anchor):
4.402 + self.out("<a name='%s' />" % escape_attr(self.linker.make_id(anchor.target)))
4.403 +
4.404 + def break_(self, break_):
4.405 pass
4.406
4.407 - def comment(self, comment, extra):
4.408 + def comment(self, comment):
4.409 pass
4.410
4.411 - def directive(self, directive, extra):
4.412 + def directive(self, directive):
4.413
4.414 # Obtain a blank value if the value is missing.
4.415
4.416 - name, text = (directive.split(None, 1) + [""])[:2]
4.417 + name, text = (directive.directive.split(None, 1) + [""])[:2]
4.418
4.419 # Produce a readable redirect.
4.420
4.421 @@ -281,80 +304,51 @@
4.422
4.423 self.end_block()
4.424
4.425 - def linebreak(self):
4.426 + def linebreak(self, linebreak):
4.427 self.out("<br />")
4.428
4.429 - def _link(self, target, nodes, tag, attr):
4.430 - link = self.linker and self.linker.translate(target) or None
4.431 -
4.432 - self.out('<%s %s="%s"' % (tag, attr, escape_attr(link.get_target())))
4.433 -
4.434 - # Provide link parameters as attributes.
4.435 -
4.436 - if nodes:
4.437 - for node in nodes:
4.438 - if isinstance(node, LinkParameter):
4.439 - self.out(" ")
4.440 - node.to_string(self)
4.441 -
4.442 - # Close the tag if an image.
4.443 -
4.444 - if tag == "img":
4.445 - self.out(" />")
4.446 -
4.447 - # Provide the link label if specified. Otherwise, use a generated
4.448 - # default for the label.
4.449 + def link(self, link):
4.450 + self._link(link.target, link.nodes, "a", "href")
4.451
4.452 - else:
4.453 - self.out(">")
4.454 -
4.455 - for node in nodes or []:
4.456 - if isinstance(node, LinkLabel):
4.457 - node.to_string(self)
4.458 - break
4.459 - else:
4.460 - self.out(escape_text(link.get_label()))
4.461 + def link_label(self, link_label):
4.462 + self.container(link_label)
4.463
4.464 - self.out("</%s>" % tag)
4.465 -
4.466 - def link(self, target, nodes):
4.467 - self._link(target, nodes, "a", "href")
4.468 + def link_parameter(self, link_parameter):
4.469 + s = link_parameter.text_content()
4.470 + key_value = s.split("=", 1)
4.471
4.472 - def link_label(self, nodes):
4.473 - for node in nodes:
4.474 - node.to_string(self)
4.475 -
4.476 - def link_parameter(self, key_value):
4.477 if len(key_value) == 1:
4.478 self.out(key_value[0])
4.479 else:
4.480 key, value = key_value
4.481 self.out("%s='%s'" % (key, escape_attr(value)))
4.482
4.483 - def nbsp(self):
4.484 + def nbsp(self, nbsp):
4.485 self.out(" ")
4.486
4.487 - def rule(self, height):
4.488 - self.out("<hr style='height: %dpt' />" % min(height, 10))
4.489 + def rule(self, rule):
4.490 + self.out("<hr style='height: %dpt' />" % min(rule.height, 10))
4.491
4.492 - def table_attrs(self, nodes):
4.493 + def table_attrs(self, table_attrs):
4.494
4.495 # Skip the attributes in their original form.
4.496
4.497 pass
4.498
4.499 - def table_attr(self, name, value, concise, quote):
4.500 - self.out(" %s%s" % (escape_text(name), value is not None and
4.501 - "='%s'" % escape_attr(value) or ""))
4.502 + def table_attr(self, table_attr):
4.503 + self.out(" %s%s" % (
4.504 + escape_text(table_attr.name),
4.505 + table_attr.value is not None and
4.506 + "='%s'" % escape_attr(table_attr.value) or ""))
4.507
4.508 - def text(self, s):
4.509 - self.out(escape_text(s))
4.510 + def text(self, text):
4.511 + self.out(escape_text(text.s))
4.512
4.513 - def transclusion(self, target, nodes):
4.514 - self._link(target, nodes, "img", "src")
4.515 + def transclusion(self, transclusion):
4.516 + self._link(transclusion.target, transclusion.nodes, "img", "src")
4.517
4.518 - def verbatim(self, s):
4.519 - self.text(s)
4.520 + def verbatim(self, verbatim):
4.521 + self.out(escape_text(verbatim.text))
4.522
4.523 serialiser = HTMLSerialiser
4.524
5.1 --- a/moinformat/serialisers/html/table.py Tue Jun 20 18:58:47 2023 +0200
5.2 +++ b/moinformat/serialisers/html/table.py Wed Jun 28 16:12:26 2023 +0200
5.3 @@ -28,7 +28,7 @@
5.4
5.5 input_formats = ["table"]
5.6
5.7 - def continuation(self, text):
5.8 + def continuation(self, continuation):
5.9 self.out(" ")
5.10
5.11 serialiser = HTMLTableSerialiser
6.1 --- a/moinformat/serialisers/moin/graphviz.py Tue Jun 20 18:58:47 2023 +0200
6.2 +++ b/moinformat/serialisers/moin/graphviz.py Wed Jun 28 16:12:26 2023 +0200
6.3 @@ -3,7 +3,7 @@
6.4 """
6.5 Moin Graphviz region serialiser.
6.6
6.7 -Copyright (C) 2018, 2021 Paul Boddie <paul@boddie.org.uk>
6.8 +Copyright (C) 2018, 2021, 2023 Paul Boddie <paul@boddie.org.uk>
6.9
6.10 This program is free software; you can redistribute it and/or modify it under
6.11 the terms of the GNU General Public License as published by the Free Software
6.12 @@ -28,20 +28,19 @@
6.13 input_formats = ["graphviz", "dot"]
6.14 formats = ["moin", "wiki"]
6.15
6.16 - def start_block(self):
6.17 - pass
6.18 -
6.19 - def end_block(self):
6.20 - pass
6.21 + def block(self, block):
6.22 + self.container(block)
6.23
6.24 - def directive(self, key, value, directive):
6.25 - if directive:
6.26 - self.out("#%s\n" % directive)
6.27 + def directive(self, directive):
6.28 + if directive.directive:
6.29 + self.out("#%s\n" % directive.directive)
6.30 else:
6.31 - self.out("//%s%s\n" % (value and "%s=" % key or key, value or ""))
6.32 + self.out("//%s%s\n" % (
6.33 + directive.value and "%s=" % directive.key or directive.key,
6.34 + directive.value or ""))
6.35
6.36 def text(self, text):
6.37 - self.out(text)
6.38 + self.out(text.s)
6.39
6.40 serialiser = MoinGraphvizSerialiser
6.41
7.1 --- a/moinformat/serialisers/moin/moin.py Tue Jun 20 18:58:47 2023 +0200
7.2 +++ b/moinformat/serialisers/moin/moin.py Wed Jun 28 16:12:26 2023 +0200
7.3 @@ -3,7 +3,7 @@
7.4 """
7.5 Moin wiki text serialiser.
7.6
7.7 -Copyright (C) 2017, 2018, 2021, 2022 Paul Boddie <paul@boddie.org.uk>
7.8 +Copyright (C) 2017, 2018, 2021, 2022, 2023 Paul Boddie <paul@boddie.org.uk>
7.9
7.10 This program is free software; you can redistribute it and/or modify it under
7.11 the terms of the GNU General Public License as published by the Free Software
7.12 @@ -28,224 +28,216 @@
7.13 input_formats = ["moin", "wiki"]
7.14 formats = ["moin", "wiki"]
7.15
7.16 - def start_region(self, level, indent, type, args, extra):
7.17 + # Node handler methods.
7.18 +
7.19 + def region(self, region):
7.20 out = self.out
7.21 - if level:
7.22 - out(" " * indent + "{" * level)
7.23
7.24 - # Produce a header for regions within a top-level region.
7.25 + if region.level:
7.26 + out(" " * region.indent + "{" * region.level)
7.27
7.28 - if type and type != "inline" and level:
7.29 + # Produce a header for regions within a top-level region.
7.30
7.31 - # Obtain individual arguments, excluding the region type.
7.32 + if region.type and region.type != "inline":
7.33 +
7.34 + # Obtain individual arguments, excluding the region type.
7.35
7.36 - args = args.split(" ")[1:]
7.37 - args_str = args and (" %s" % " ".join(args)) or ""
7.38 + args = region.args.split(" ")[1:]
7.39 + args_str = args and (" %s" % " ".join(args)) or ""
7.40
7.41 - out("#!%s%s\n" % (type, args_str))
7.42 + out("#!%s%s\n" % (region.type, args_str))
7.43 +
7.44 + # Serialise the region content.
7.45
7.46 - def end_region(self, level, indent, type, args, extra):
7.47 - out = self.out
7.48 - if level:
7.49 - out("%s%s" % ("}" * level, extra or ""))
7.50 + self.region_to_string(region)
7.51
7.52 - def start_block(self):
7.53 - pass
7.54 + if region.level:
7.55 + out("%s%s" % ("}" * region.level, region.extra or ""))
7.56
7.57 - def end_block(self):
7.58 - pass
7.59 + # Block node methods.
7.60
7.61 - def start_defitem(self, pad, extra):
7.62 - self.out((extra and extra + "::" or "") + pad)
7.63 -
7.64 - def end_defitem(self, pad, extra):
7.65 - pass
7.66 + def block(self, block):
7.67 + self.container(block)
7.68
7.69 - def start_defterm(self, pad, extra):
7.70 - self.out(pad)
7.71 + def defitem(self, defitem):
7.72 + self.out((defitem.extra and defitem.extra + "::" or "") + defitem.pad)
7.73 + self.container(defitem)
7.74
7.75 - def end_defterm(self, pad, extra):
7.76 - self.out("::" + extra)
7.77 + def defterm(self, defterm):
7.78 + self.out(defterm.pad)
7.79 + self.container(defterm)
7.80 + self.out("::" + defterm.extra)
7.81
7.82 - def start_emphasis(self):
7.83 - self.out("''")
7.84 -
7.85 - def end_emphasis(self):
7.86 - self.out("''")
7.87 + def fontstyle(self, fontstyle):
7.88 + if fontstyle.emphasis:
7.89 + self.out("''")
7.90 + elif fontstyle.strong:
7.91 + self.out("'''")
7.92 + self.container(fontstyle)
7.93 + if fontstyle.emphasis:
7.94 + self.out("''")
7.95 + elif fontstyle.strong:
7.96 + self.out("'''")
7.97
7.98 - def start_heading(self, level, extra, pad, identifier):
7.99 - self.out(extra + "=" * level + pad)
7.100 + def heading(self, heading):
7.101 + self.out(heading.start_extra + "=" * heading.level + heading.start_pad)
7.102 + self.container(heading)
7.103 + self.out(heading.end_pad + "=" * heading.level + heading.end_extra)
7.104
7.105 - def end_heading(self, level, pad, extra):
7.106 - self.out(pad + "=" * level + extra)
7.107 -
7.108 - def start_larger(self):
7.109 + def larger(self, larger):
7.110 self.out("~+")
7.111 -
7.112 - def end_larger(self):
7.113 + self.container(larger)
7.114 self.out("+~")
7.115
7.116 - def start_list(self, indent, marker, num):
7.117 - pass
7.118 -
7.119 - def end_list(self, indent, marker, num):
7.120 - pass
7.121 + def list(self, list):
7.122 + self.container(list)
7.123
7.124 - def start_listitem(self, indent, marker, space, num):
7.125 - self.out("%s%s%s%s" % (indent * " ", marker, num and "#%s" % num or "", space))
7.126 + def listitem(self, listitem):
7.127 + self.out("%s%s%s%s" % (
7.128 + listitem.indent * " ",
7.129 + listitem.marker,
7.130 + listitem.num and "#%s" % listitem.num or "",
7.131 + listitem.space))
7.132 + self.container(listitem)
7.133
7.134 - def end_listitem(self, indent, marker, space, num):
7.135 - pass
7.136 -
7.137 - def start_macro(self, name, args, nodes, inline):
7.138 + def macro(self, macro):
7.139
7.140 # Special case of a deliberately unexpanded macro.
7.141
7.142 - if nodes is None:
7.143 + if macro.nodes is None:
7.144 return
7.145
7.146 # Fallback case for when macros are not replaced.
7.147
7.148 - if not nodes:
7.149 - self.out("<<%s%s>>" % (name, args and "(%s)" % ",".join(args) or ""))
7.150 + if not macro.nodes:
7.151 + self.out("<<%s%s>>" % (macro.name, macro.args and "(%s)" % ",".join(macro.args) or ""))
7.152
7.153 - def end_macro(self, inline):
7.154 - pass
7.155 -
7.156 - def start_monospace(self):
7.157 + def monospace(self, monospace):
7.158 + self.out("`")
7.159 + self.container(monospace)
7.160 self.out("`")
7.161
7.162 - def end_monospace(self):
7.163 - self.out("`")
7.164 -
7.165 - def start_smaller(self):
7.166 + def smaller(self, smaller):
7.167 self.out("~-")
7.168 -
7.169 - def end_smaller(self):
7.170 + self.container(smaller)
7.171 self.out("-~")
7.172
7.173 - def start_strong(self):
7.174 - self.out("'''")
7.175 -
7.176 - def end_strong(self):
7.177 - self.out("'''")
7.178 -
7.179 - def start_strikethrough(self):
7.180 + def strikethrough(self, strikethrough):
7.181 self.out("--(")
7.182 -
7.183 - def end_strikethrough(self):
7.184 + self.container(strikethrough)
7.185 self.out(")--")
7.186
7.187 - def start_subscript(self):
7.188 + def subscript(self, subscript):
7.189 + self.out(",,")
7.190 + self.container(subscript)
7.191 self.out(",,")
7.192
7.193 - def end_subscript(self):
7.194 - self.out(",,")
7.195 -
7.196 - def start_superscript(self):
7.197 + def superscript(self, superscript):
7.198 self.out("^")
7.199 -
7.200 - def end_superscript(self):
7.201 + self.container(superscript)
7.202 self.out("^")
7.203
7.204 - def start_table(self):
7.205 - pass
7.206 -
7.207 - def end_table(self):
7.208 - pass
7.209 + def table(self, table):
7.210 + self.container(table)
7.211
7.212 - def start_table_attrs(self):
7.213 - self.out("<")
7.214 -
7.215 - def end_table_attrs(self):
7.216 - self.out(">")
7.217 + def table_cell(self, table_cell):
7.218 + self.out("||")
7.219 + self.container(table_cell)
7.220
7.221 - def start_table_cell(self, attrs, leading, padding):
7.222 + def table_row(self, table_row):
7.223 + self.container(table_row)
7.224 self.out("||")
7.225 -
7.226 - def end_table_cell(self):
7.227 - pass
7.228 + self.out(table_row.trailing)
7.229
7.230 - def start_table_row(self, leading, padding):
7.231 - pass
7.232 -
7.233 - def end_table_row(self, trailing):
7.234 - self.out("||")
7.235 - self.out(trailing)
7.236 -
7.237 - def start_underline(self):
7.238 + def underline(self, underline):
7.239 + self.out("__")
7.240 + self.container(underline)
7.241 self.out("__")
7.242
7.243 - def end_underline(self):
7.244 - self.out("__")
7.245 + # Inline node methods.
7.246
7.247 - def anchor(self, target):
7.248 - self.out("((%s))" % target)
7.249 + def anchor(self, anchor):
7.250 + self.out("((%s))" % anchor.target)
7.251
7.252 - def break_(self):
7.253 + def break_(self, break_):
7.254 self.out("\n")
7.255
7.256 - def comment(self, comment, extra):
7.257 - self.out("##%s%s" % (comment, extra))
7.258 + def comment(self, comment):
7.259 + self.out("##%s%s" % (comment.comment, comment.extra))
7.260
7.261 - def directive(self, directive, extra):
7.262 - self.out("#%s%s" % (directive, extra))
7.263 + def directive(self, directive):
7.264 + self.out("#%s%s" % (directive.directive, directive.extra))
7.265
7.266 - def linebreak(self):
7.267 + def linebreak(self, linebreak):
7.268 self.out(r"\\")
7.269
7.270 - def link(self, target, nodes):
7.271 - self.out("[[%s" % target)
7.272 - for node in nodes:
7.273 + def link(self, link):
7.274 + self.out("[[%s" % link.target)
7.275 + for node in link.nodes:
7.276 self.out("|")
7.277 - node.to_string(self)
7.278 + node.visit(self)
7.279 self.out("]]")
7.280
7.281 - def link_label(self, nodes):
7.282 - for node in nodes:
7.283 - node.to_string(self)
7.284 + def link_label(self, link_label):
7.285 + self.container(link_label)
7.286
7.287 - def link_parameter(self, key_value):
7.288 + def link_parameter(self, link_parameter):
7.289 + s = link_parameter.text_content()
7.290 + key_value = s.split("=", 1)
7.291 +
7.292 if len(key_value) == 1:
7.293 self.out(key_value[0])
7.294 else:
7.295 self.out("=".join(key_value))
7.296
7.297 - def nbsp(self):
7.298 + def nbsp(self, nbsp):
7.299 self.out(r"\_")
7.300
7.301 - def rule(self, height):
7.302 - self.out("-" * (height + 4))
7.303 + def rule(self, rule):
7.304 + self.out("-" * (rule.height + 4))
7.305
7.306 - def table_attrs(self, nodes):
7.307 - for node in nodes:
7.308 - node.to_string(self)
7.309 + def table_attrs(self, table_attrs):
7.310 + self.out("<")
7.311 + self.container(table_attrs)
7.312 + if not table_attrs.incomplete:
7.313 + self.out(">")
7.314
7.315 - def table_attr(self, name, value, concise, quote):
7.316 - if concise:
7.317 - if name == "bgcolor": self.out(value)
7.318 - elif name == "colspan": self.out("-%s" % value)
7.319 - elif name == "align" : self.out(value == "left" and "(" or value == "right" and ")" or ":")
7.320 - elif name == "rowspan": self.out("|%s" % value)
7.321 - elif name == "valign" : self.out(value == "top" and "^" or "v")
7.322 - elif name == "width" : self.out(value)
7.323 + def table_attr(self, table_attr):
7.324 + if table_attr.concise:
7.325 + if table_attr.name == "bgcolor":
7.326 + self.out(table_attr.value)
7.327 + elif table_attr.name == "colspan":
7.328 + self.out("-%s" % table_attr.value)
7.329 + elif table_attr.name == "align":
7.330 + self.out(table_attr.value == "left" and "(" or table_attr.value == "right" and ")" or ":")
7.331 + elif table_attr.name == "rowspan":
7.332 + self.out("|%s" % table_attr.value)
7.333 + elif table_attr.name == "valign":
7.334 + self.out(table_attr.value == "top" and "^" or "v")
7.335 + elif table_attr.name == "width":
7.336 + self.out(table_attr.value)
7.337 else:
7.338 - self.out("%s%s" % (escape_text(name), value is not None and
7.339 - "=%s%s%s" % (quote or '"', escape_attr(value), quote or '"') or ""))
7.340 -
7.341 - def text(self, s):
7.342 - self.out(s)
7.343 + self.out("%s%s" % (
7.344 + escape_text(table_attr.name),
7.345 + table_attr.value is not None and "=%s%s%s" % (
7.346 + table_attr.quote or '"',
7.347 + escape_attr(table_attr.value),
7.348 + table_attr.quote or '"')
7.349 + or ""))
7.350
7.351 - def transclusion(self, target, nodes):
7.352 - self.out("{{%s" % target)
7.353 - for node in nodes:
7.354 + def text(self, text):
7.355 + self.out(text.s)
7.356 +
7.357 + def transclusion(self, transclusion):
7.358 + self.out("{{%s" % transclusion.target)
7.359 + for node in transclusion.nodes:
7.360 self.out("|")
7.361 - node.to_string(self)
7.362 + node.visit(self)
7.363 self.out("}}")
7.364
7.365 - def verbatim(self, text):
7.366 + def verbatim(self, verbatim):
7.367 self.out("<<<")
7.368 - self.out(text)
7.369 + self.out(verbatim.text)
7.370 self.out(">>>")
7.371
7.372 serialiser = MoinSerialiser
8.1 --- a/moinformat/serialisers/moin/table.py Tue Jun 20 18:58:47 2023 +0200
8.2 +++ b/moinformat/serialisers/moin/table.py Wed Jun 28 16:12:26 2023 +0200
8.3 @@ -3,7 +3,7 @@
8.4 """
8.5 Moin wiki table serialiser.
8.6
8.7 -Copyright (C) 2017, 2018, 2021 Paul Boddie <paul@boddie.org.uk>
8.8 +Copyright (C) 2017, 2018, 2021, 2023 Paul Boddie <paul@boddie.org.uk>
8.9
8.10 This program is free software; you can redistribute it and/or modify it under
8.11 the terms of the GNU General Public License as published by the Free Software
8.12 @@ -31,31 +31,35 @@
8.13 self.first_cell = False
8.14 self.first_row = False
8.15
8.16 - def start_table(self):
8.17 + def table(self, table):
8.18 self.first_row = True
8.19 + self.container(table)
8.20
8.21 - def start_table_cell(self, attrs, leading, padding):
8.22 + def table_cell(self, table_cell):
8.23 if not self.first_cell:
8.24 - self.out(leading)
8.25 + self.out(table_cell.leading)
8.26 self.out("||")
8.27 else:
8.28 self.first_cell = False
8.29 - self.out(padding)
8.30
8.31 - def start_table_row(self, leading, padding):
8.32 + self.out(table_cell.padding)
8.33 + self.container(table_cell)
8.34 +
8.35 + def table_row(self, table_row):
8.36 self.first_cell = True
8.37 +
8.38 if not self.first_row:
8.39 - self.out(leading)
8.40 + self.out(table_row.leading)
8.41 self.out("==")
8.42 - self.out(padding)
8.43 + self.out(table_row.padding)
8.44 else:
8.45 self.first_row = False
8.46
8.47 - def end_table_row(self, trailing):
8.48 - self.out(trailing)
8.49 + self.container(table_row)
8.50 + self.out(table_row.trailing)
8.51
8.52 - def continuation(self, text):
8.53 - self.out(text)
8.54 + def continuation(self, continuation):
8.55 + self.out(continuation.text)
8.56
8.57 serialiser = MoinTableSerialiser
8.58
9.1 --- a/moinformat/tree/graphviz.py Tue Jun 20 18:58:47 2023 +0200
9.2 +++ b/moinformat/tree/graphviz.py Wed Jun 28 16:12:26 2023 +0200
9.3 @@ -3,7 +3,7 @@
9.4 """
9.5 Graphviz document tree nodes.
9.6
9.7 -Copyright (C) 2018 Paul Boddie <paul@boddie.org.uk>
9.8 +Copyright (C) 2018, 2023 Paul Boddie <paul@boddie.org.uk>
9.9
9.10 This program is free software; you can redistribute it and/or modify it under
9.11 the terms of the GNU General Public License as published by the Free Software
9.12 @@ -42,7 +42,7 @@
9.13 def prettyprint(self, indent=""):
9.14 return "%sDirective: key=%r value=%r directive=%r" % (indent, self.key, self.value, self.directive)
9.15
9.16 - def to_string(self, out):
9.17 - out.directive(self.key, self.value, self.directive)
9.18 + def visit(self, visitor):
9.19 + visitor.directive(self)
9.20
9.21 # vim: tabstop=4 expandtab shiftwidth=4
10.1 --- a/moinformat/tree/moin.py Tue Jun 20 18:58:47 2023 +0200
10.2 +++ b/moinformat/tree/moin.py Wed Jun 28 16:12:26 2023 +0200
10.3 @@ -3,7 +3,8 @@
10.4 """
10.5 Moin wiki format document tree nodes.
10.6
10.7 -Copyright (C) 2017, 2018, 2019, 2020, 2021, 2022 Paul Boddie <paul@boddie.org.uk>
10.8 +Copyright (C) 2017, 2018, 2019, 2020, 2021, 2022,
10.9 + 2023 Paul Boddie <paul@boddie.org.uk>
10.10
10.11 This program is free software; you can redistribute it and/or modify it under
10.12 the terms of the GNU General Public License as published by the Free Software
10.13 @@ -182,10 +183,6 @@
10.14 l.append(node.prettyprint(indent + " "))
10.15 return "\n".join(l)
10.16
10.17 - def _to_string(self, out):
10.18 - for node in self.nodes:
10.19 - node.to_string(out)
10.20 -
10.21 class Region(Container):
10.22
10.23 "A region of the page."
10.24 @@ -221,23 +218,8 @@
10.25 self.level, self.indent, self.type, self.args, self.extra)]
10.26 return self._prettyprint(l, indent)
10.27
10.28 - def to_string(self, out):
10.29 - out.start_region(self.level, self.indent, self.type, self.args, self.extra)
10.30 -
10.31 - # Obtain a serialiser for the region from the same format family.
10.32 - # Retain the same serialiser if no appropriate serialiser could be
10.33 - # obtained.
10.34 -
10.35 - serialiser_name = "%s.%s" % (out.formats[0], self.type)
10.36 - serialiser = out.get_serialiser(serialiser_name)
10.37 -
10.38 - # Serialise the region.
10.39 -
10.40 - self._to_string(serialiser)
10.41 -
10.42 - # End the region with the previous serialiser.
10.43 -
10.44 - out.end_region(self.level, self.indent, self.type, self.args, self.extra)
10.45 + def visit(self, visitor):
10.46 + visitor.region(self)
10.47
10.48
10.49
10.50 @@ -254,10 +236,8 @@
10.51 l = ["%sBlock" % indent]
10.52 return self._prettyprint(l, indent)
10.53
10.54 - def to_string(self, out):
10.55 - out.start_block()
10.56 - self._to_string(out)
10.57 - out.end_block()
10.58 + def visit(self, visitor):
10.59 + visitor.block(self)
10.60
10.61 class DefItem(Container):
10.62
10.63 @@ -275,10 +255,8 @@
10.64 l = ["%sDefItem: pad=%r extra=%r" % (indent, self.pad, self.extra)]
10.65 return self._prettyprint(l, indent)
10.66
10.67 - def to_string(self, out):
10.68 - out.start_defitem(self.pad, self.extra)
10.69 - self._to_string(out)
10.70 - out.end_defitem(self.pad, self.extra)
10.71 + def visit(self, visitor):
10.72 + visitor.defitem(self)
10.73
10.74 class DefTerm(Container):
10.75
10.76 @@ -296,10 +274,8 @@
10.77 l = ["%sDefTerm: pad=%r extra=%r" % (indent, self.pad, self.extra)]
10.78 return self._prettyprint(l, indent)
10.79
10.80 - def to_string(self, out):
10.81 - out.start_defterm(self.pad, self.extra)
10.82 - self._to_string(out)
10.83 - out.end_defterm(self.pad, self.extra)
10.84 + def visit(self, visitor):
10.85 + visitor.defterm(self)
10.86
10.87 class FontStyle(Container):
10.88
10.89 @@ -331,16 +307,8 @@
10.90 l = ["%sFontStyle: emphasis=%r strong=%r" % (indent, self.emphasis, self.strong)]
10.91 return self._prettyprint(l, indent)
10.92
10.93 - def to_string(self, out):
10.94 - if self.emphasis:
10.95 - out.start_emphasis()
10.96 - elif self.strong:
10.97 - out.start_strong()
10.98 - self._to_string(out)
10.99 - if self.emphasis:
10.100 - out.end_emphasis()
10.101 - elif self.strong:
10.102 - out.end_strong()
10.103 + def visit(self, visitor):
10.104 + visitor.fontstyle(self)
10.105
10.106 class Heading(Container):
10.107
10.108 @@ -368,10 +336,8 @@
10.109 self.end_extra, self.identifier)]
10.110 return self._prettyprint(l, indent)
10.111
10.112 - def to_string(self, out):
10.113 - out.start_heading(self.level, self.start_extra, self.start_pad, self.identifier)
10.114 - self._to_string(out)
10.115 - out.end_heading(self.level, self.end_pad, self.end_extra)
10.116 + def visit(self, visitor):
10.117 + visitor.heading(self)
10.118
10.119 class LinkLabel(Container):
10.120
10.121 @@ -384,8 +350,8 @@
10.122 l = ["%sLinkLabel" % indent]
10.123 return self._prettyprint(l, indent)
10.124
10.125 - def to_string(self, out):
10.126 - out.link_label(self.nodes)
10.127 + def visit(self, visitor):
10.128 + visitor.link_label(self)
10.129
10.130 class LinkParameter(Container):
10.131
10.132 @@ -398,10 +364,8 @@
10.133 l = ["%sLinkParameter" % indent]
10.134 return self._prettyprint(l, indent)
10.135
10.136 - def to_string(self, out):
10.137 - s = self.text_content()
10.138 - t = s.split("=", 1)
10.139 - out.link_parameter(t)
10.140 + def visit(self, visitor):
10.141 + visitor.link_parameter(self)
10.142
10.143 class List(Container):
10.144
10.145 @@ -426,12 +390,10 @@
10.146 l = ["%sList: indent=%r marker=%r num=%r" % (indent, self.indent, self.marker, self.num)]
10.147 return self._prettyprint(l, indent)
10.148
10.149 - def to_string(self, out):
10.150 + def visit(self, visitor):
10.151 if not self.first:
10.152 self.init()
10.153 - out.start_list(self.indent, self.marker, self.num)
10.154 - self._to_string(out)
10.155 - out.end_list(self.indent, self.marker, self.num)
10.156 + visitor.list(self)
10.157
10.158 class ListItem(Container):
10.159
10.160 @@ -455,10 +417,8 @@
10.161 l = ["%sListItem: indent=%d marker=%r space=%r num=%r" % (indent, self.indent, self.marker, self.space, self.num)]
10.162 return self._prettyprint(l, indent)
10.163
10.164 - def to_string(self, out):
10.165 - out.start_listitem(self.indent, self.marker, self.space, self.num)
10.166 - self._to_string(out)
10.167 - out.end_listitem(self.indent, self.marker, self.space, self.num)
10.168 + def visit(self, visitor):
10.169 + visitor.listitem(self)
10.170
10.171 class TableAttrs(Container):
10.172
10.173 @@ -480,11 +440,8 @@
10.174 l = ["%sTableAttrs:" % indent]
10.175 return self._prettyprint(l, indent)
10.176
10.177 - def to_string(self, out):
10.178 - out.start_table_attrs()
10.179 - out.table_attrs(self.nodes)
10.180 - if not self.incomplete:
10.181 - out.end_table_attrs()
10.182 + def visit(self, visitor):
10.183 + visitor.table_attrs(self)
10.184
10.185 class Table(Container):
10.186
10.187 @@ -497,10 +454,8 @@
10.188 l = ["%sTable:" % indent]
10.189 return self._prettyprint(l, indent)
10.190
10.191 - def to_string(self, out):
10.192 - out.start_table()
10.193 - self._to_string(out)
10.194 - out.end_table()
10.195 + def visit(self, visitor):
10.196 + visitor.table(self)
10.197
10.198 class TableCell(Container):
10.199
10.200 @@ -521,10 +476,8 @@
10.201 self.padding)]
10.202 return self._prettyprint(l, indent)
10.203
10.204 - def to_string(self, out):
10.205 - out.start_table_cell(self.attrs, self.leading, self.padding)
10.206 - self._to_string(out)
10.207 - out.end_table_cell()
10.208 + def visit(self, visitor):
10.209 + visitor.table_cell(self)
10.210
10.211 class TableRow(Container):
10.212
10.213 @@ -545,10 +498,8 @@
10.214 indent, self.trailing, self.leading, self.padding)]
10.215 return self._prettyprint(l, indent)
10.216
10.217 - def to_string(self, out):
10.218 - out.start_table_row(self.leading, self.padding)
10.219 - self._to_string(out)
10.220 - out.end_table_row(self.trailing)
10.221 + def visit(self, visitor):
10.222 + visitor.table_row(self)
10.223
10.224
10.225
10.226 @@ -569,10 +520,8 @@
10.227
10.228 "Larger text."
10.229
10.230 - def to_string(self, out):
10.231 - out.start_larger()
10.232 - self._to_string(out)
10.233 - out.end_larger()
10.234 + def visit(self, visitor):
10.235 + visitor.larger(self)
10.236
10.237 class Link(Container):
10.238
10.239 @@ -589,8 +538,8 @@
10.240 l = ["%sLink: target=%r" % (indent, self.target)]
10.241 return self._prettyprint(l, indent)
10.242
10.243 - def to_string(self, out):
10.244 - out.link(self.target, self.nodes)
10.245 + def visit(self, visitor):
10.246 + visitor.link(self)
10.247
10.248 class Macro(Container):
10.249
10.250 @@ -613,56 +562,43 @@
10.251 l = ["%sMacro: name=%r args=%r" % (indent, self.name, self.args)]
10.252 return self._prettyprint(l, indent)
10.253
10.254 - def to_string(self, out):
10.255 - out.start_macro(self.name, self.args, self.nodes, self.inline)
10.256 - if self.nodes:
10.257 - self._to_string(out)
10.258 - out.end_macro(self.inline)
10.259 + def visit(self, visitor):
10.260 + visitor.macro(self)
10.261
10.262 class Monospace(Inline):
10.263
10.264 "Monospaced text."
10.265
10.266 - def to_string(self, out):
10.267 - out.start_monospace()
10.268 - self._to_string(out)
10.269 - out.end_monospace()
10.270 + def visit(self, visitor):
10.271 + visitor.monospace(self)
10.272
10.273 class Smaller(Inline):
10.274
10.275 "Smaller text."
10.276
10.277 - def to_string(self, out):
10.278 - out.start_smaller()
10.279 - self._to_string(out)
10.280 - out.end_smaller()
10.281 + def visit(self, visitor):
10.282 + visitor.smaller(self)
10.283
10.284 class Strikethrough(Inline):
10.285
10.286 - "Crossed-out text."
10.287 + "Crossed-visitor text."
10.288
10.289 - def to_string(self, out):
10.290 - out.start_strikethrough()
10.291 - self._to_string(out)
10.292 - out.end_strikethrough()
10.293 + def visit(self, visitor):
10.294 + visitor.strikethrough(self)
10.295
10.296 class Subscript(Inline):
10.297
10.298 "Subscripted text."
10.299
10.300 - def to_string(self, out):
10.301 - out.start_subscript()
10.302 - self._to_string(out)
10.303 - out.end_subscript()
10.304 + def visit(self, visitor):
10.305 + visitor.subscript(self)
10.306
10.307 class Superscript(Inline):
10.308
10.309 "Superscripted text."
10.310
10.311 - def to_string(self, out):
10.312 - out.start_superscript()
10.313 - self._to_string(out)
10.314 - out.end_superscript()
10.315 + def visit(self, visitor):
10.316 + visitor.superscript(self)
10.317
10.318 class Transclusion(Container):
10.319
10.320 @@ -679,17 +615,15 @@
10.321 l = ["%sTransclusion: target=%r" % (indent, self.target)]
10.322 return self._prettyprint(l, indent)
10.323
10.324 - def to_string(self, out):
10.325 - out.transclusion(self.target, self.nodes)
10.326 + def visit(self, visitor):
10.327 + visitor.transclusion(self)
10.328
10.329 class Underline(Inline):
10.330
10.331 "Underlined text."
10.332
10.333 - def to_string(self, out):
10.334 - out.start_underline()
10.335 - self._to_string(out)
10.336 - out.end_underline()
10.337 + def visit(self, visitor):
10.338 + visitor.underline(self)
10.339
10.340
10.341
10.342 @@ -715,8 +649,8 @@
10.343 def prettyprint(self, indent=""):
10.344 return "%sAnchor: target=%r" % (indent, self.target)
10.345
10.346 - def to_string(self, out):
10.347 - out.anchor(self.target)
10.348 + def visit(self, visitor):
10.349 + visitor.anchor(self)
10.350
10.351 class Break(Node):
10.352
10.353 @@ -728,8 +662,8 @@
10.354 def prettyprint(self, indent=""):
10.355 return "%sBreak" % indent
10.356
10.357 - def to_string(self, out):
10.358 - out.break_()
10.359 + def visit(self, visitor):
10.360 + visitor.break_(self)
10.361
10.362 class Comment(Node):
10.363
10.364 @@ -745,8 +679,8 @@
10.365 def prettyprint(self, indent=""):
10.366 return "%sComment: comment=%r extra=%r" % (indent, self.comment, self.extra)
10.367
10.368 - def to_string(self, out):
10.369 - out.comment(self.comment, self.extra)
10.370 + def visit(self, visitor):
10.371 + visitor.comment(self)
10.372
10.373 class Directive(Node):
10.374
10.375 @@ -762,8 +696,8 @@
10.376 def prettyprint(self, indent=""):
10.377 return "%sDirective: directive=%r extra=%r" % (indent, self.directive, self.extra)
10.378
10.379 - def to_string(self, out):
10.380 - out.directive(self.directive, self.extra)
10.381 + def visit(self, visitor):
10.382 + visitor.directive(self)
10.383
10.384 class LineBreak(Node):
10.385
10.386 @@ -775,8 +709,8 @@
10.387 def prettyprint(self, indent=""):
10.388 return "%sLineBreak" % indent
10.389
10.390 - def to_string(self, out):
10.391 - out.linebreak()
10.392 + def visit(self, visitor):
10.393 + visitor.linebreak(self)
10.394
10.395 class NonBreakingSpace(Node):
10.396
10.397 @@ -788,8 +722,8 @@
10.398 def prettyprint(self, indent=""):
10.399 return "%sNonBreakingSpace" % indent
10.400
10.401 - def to_string(self, out):
10.402 - out.nbsp()
10.403 + def visit(self, visitor):
10.404 + visitor.nbsp(self)
10.405
10.406 class Rule(Node):
10.407
10.408 @@ -804,8 +738,8 @@
10.409 def prettyprint(self, indent=""):
10.410 return "%sRule: height=%d" % (indent, self.height)
10.411
10.412 - def to_string(self, out):
10.413 - out.rule(self.height)
10.414 + def visit(self, visitor):
10.415 + visitor.rule(self)
10.416
10.417 class TableAttr(Node):
10.418
10.419 @@ -823,8 +757,8 @@
10.420 def prettyprint(self, indent=""):
10.421 return "%sTableAttr: name=%r value=%r concise=%r quote=%r" % (indent, self.name, self.value, self.concise, self.quote)
10.422
10.423 - def to_string(self, out):
10.424 - out.table_attr(self.name, self.value, self.concise, self.quote)
10.425 + def visit(self, visitor):
10.426 + visitor.table_attr(self)
10.427
10.428 class Text(Node):
10.429
10.430 @@ -848,8 +782,8 @@
10.431 def prettyprint(self, indent=""):
10.432 return "%sText: %r" % (indent, self.s)
10.433
10.434 - def to_string(self, out):
10.435 - out.text(self.s)
10.436 + def visit(self, visitor):
10.437 + visitor.text(self)
10.438
10.439 class Verbatim(Node):
10.440
10.441 @@ -864,7 +798,7 @@
10.442 def prettyprint(self, indent=""):
10.443 return "%sVerbatim: text=%r" % (indent, self.text)
10.444
10.445 - def to_string(self, out):
10.446 - out.verbatim(self.text)
10.447 + def visit(self, visitor):
10.448 + visitor.verbatim(self)
10.449
10.450 # vim: tabstop=4 expandtab shiftwidth=4
11.1 --- a/moinformat/tree/table.py Tue Jun 20 18:58:47 2023 +0200
11.2 +++ b/moinformat/tree/table.py Wed Jun 28 16:12:26 2023 +0200
11.3 @@ -3,7 +3,7 @@
11.4 """
11.5 Extended table syntax document tree nodes.
11.6
11.7 -Copyright (C) 2018 Paul Boddie <paul@boddie.org.uk>
11.8 +Copyright (C) 2018, 2023 Paul Boddie <paul@boddie.org.uk>
11.9
11.10 This program is free software; you can redistribute it and/or modify it under
11.11 the terms of the GNU General Public License as published by the Free Software
11.12 @@ -34,7 +34,7 @@
11.13 def prettyprint(self, indent=""):
11.14 return "%sContinuation: %r" % (indent, self.text)
11.15
11.16 - def to_string(self, out):
11.17 - out.continuation(self.text)
11.18 + def visit(self, visitor):
11.19 + visitor.continuation(self)
11.20
11.21 # vim: tabstop=4 expandtab shiftwidth=4