1 #!/usr/bin/env python 2 3 """ 4 Moin wiki text serialiser. 5 6 Copyright (C) 2017, 2018, 2021, 2022, 2023 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 """ 21 22 from moinformat.serialisers.common import escape_attr, escape_text, Serialiser 23 24 class MoinSerialiser(Serialiser): 25 26 "Serialisation of the page." 27 28 input_formats = ["moin", "wiki"] 29 formats = ["moin", "wiki"] 30 31 # Node handler methods. 32 33 def region(self, region): 34 out = self.out 35 36 if region.level: 37 out(" " * region.indent + "{" * region.level) 38 39 # Produce a header for regions within a top-level region. 40 41 if region.type and region.type != "inline": 42 43 # Obtain individual arguments, excluding the region type. 44 45 args = region.args.split(" ")[1:] 46 args_str = args and (" %s" % " ".join(args)) or "" 47 48 out("#!%s%s\n" % (region.type, args_str)) 49 50 # Serialise the region content. 51 52 self.visit_region(region) 53 54 if region.level: 55 out("%s%s" % ("}" * region.level, region.extra or "")) 56 57 # Block node methods. 58 59 def block(self, block): 60 self.container(block) 61 62 def defitem(self, defitem): 63 self.out((defitem.extra and defitem.extra + "::" or "") + defitem.pad) 64 self.container(defitem) 65 66 def defterm(self, defterm): 67 self.out(defterm.pad) 68 self.container(defterm) 69 self.out("::" + defterm.extra) 70 71 def fontstyle(self, fontstyle): 72 if fontstyle.emphasis: 73 self.out("''") 74 elif fontstyle.strong: 75 self.out("'''") 76 self.container(fontstyle) 77 if fontstyle.emphasis: 78 self.out("''") 79 elif fontstyle.strong: 80 self.out("'''") 81 82 def heading(self, heading): 83 self.out(heading.start_extra + "=" * heading.level + heading.start_pad) 84 self.container(heading) 85 self.out(heading.end_pad + "=" * heading.level + heading.end_extra) 86 87 def larger(self, larger): 88 self.out("~+") 89 self.container(larger) 90 self.out("+~") 91 92 def list(self, list): 93 self.container(list) 94 95 def listitem(self, listitem): 96 self.out("%s%s%s%s" % ( 97 listitem.indent * " ", 98 listitem.marker, 99 listitem.num and "#%s" % listitem.num or "", 100 listitem.space)) 101 self.container(listitem) 102 103 def macro(self, macro): 104 105 # Special case of a deliberately unexpanded macro. 106 107 if macro.nodes is None: 108 return 109 110 # Fallback case for when macros are not replaced. 111 112 if not macro.nodes: 113 self.out("<<%s%s>>" % (macro.name, macro.args and "(%s)" % ",".join(macro.args) or "")) 114 115 def monospace(self, monospace): 116 self.out("`") 117 self.container(monospace) 118 self.out("`") 119 120 def smaller(self, smaller): 121 self.out("~-") 122 self.container(smaller) 123 self.out("-~") 124 125 def strikethrough(self, strikethrough): 126 self.out("--(") 127 self.container(strikethrough) 128 self.out(")--") 129 130 def subscript(self, subscript): 131 self.out(",,") 132 self.container(subscript) 133 self.out(",,") 134 135 def superscript(self, superscript): 136 self.out("^") 137 self.container(superscript) 138 self.out("^") 139 140 def table(self, table): 141 self.container(table) 142 143 def table_cell(self, table_cell): 144 self.out("||") 145 self.container(table_cell) 146 147 def table_row(self, table_row): 148 self.container(table_row) 149 self.out("||") 150 self.out(table_row.trailing) 151 152 def underline(self, underline): 153 self.out("__") 154 self.container(underline) 155 self.out("__") 156 157 # Inline node methods. 158 159 def anchor(self, anchor): 160 self.out("((%s))" % anchor.target) 161 162 def break_(self, break_): 163 self.out("\n") 164 165 def comment(self, comment): 166 self.out("##%s%s" % (comment.comment, comment.extra)) 167 168 def directive(self, directive): 169 self.out("#%s%s" % (directive.directive, directive.extra)) 170 171 def linebreak(self, linebreak): 172 self.out(r"\\") 173 174 def link(self, link): 175 self.out("[[%s" % link.target) 176 for node in link.nodes: 177 self.out("|") 178 node.visit(self) 179 self.out("]]") 180 181 def link_label(self, link_label): 182 self.container(link_label) 183 184 def link_parameter(self, link_parameter): 185 s = link_parameter.text_content() 186 key_value = s.split("=", 1) 187 188 if len(key_value) == 1: 189 self.out(key_value[0]) 190 else: 191 self.out("=".join(key_value)) 192 193 def nbsp(self, nbsp): 194 self.out(r"\_") 195 196 def rule(self, rule): 197 self.out("-" * (rule.height + 4)) 198 199 def table_attrs(self, table_attrs): 200 self.out("<") 201 self.container(table_attrs) 202 if not table_attrs.incomplete: 203 self.out(">") 204 205 def table_attr(self, table_attr): 206 if table_attr.concise: 207 if table_attr.name == "bgcolor": 208 self.out(table_attr.value) 209 elif table_attr.name == "colspan": 210 self.out("-%s" % table_attr.value) 211 elif table_attr.name == "align": 212 self.out(table_attr.value == "left" and "(" or table_attr.value == "right" and ")" or ":") 213 elif table_attr.name == "rowspan": 214 self.out("|%s" % table_attr.value) 215 elif table_attr.name == "valign": 216 self.out(table_attr.value == "top" and "^" or "v") 217 elif table_attr.name == "width": 218 self.out(table_attr.value) 219 else: 220 self.out("%s%s" % ( 221 escape_text(table_attr.name), 222 table_attr.value is not None and "=%s%s%s" % ( 223 table_attr.quote or '"', 224 escape_attr(table_attr.value), 225 table_attr.quote or '"') 226 or "")) 227 228 def text(self, text): 229 self.out(text.s) 230 231 def transclusion(self, transclusion): 232 self.out("{{%s" % transclusion.target) 233 for node in transclusion.nodes: 234 self.out("|") 235 node.visit(self) 236 self.out("}}") 237 238 def verbatim(self, verbatim): 239 self.out("<<<") 240 self.out(verbatim.text) 241 self.out(">>>") 242 243 serialiser = MoinSerialiser 244 245 # vim: tabstop=4 expandtab shiftwidth=4