Ticket #4356: trac_wiki_creole-r9337.2.patch
| File trac_wiki_creole-r9337.2.patch, 14.5 KB (added by cboos, 2 years ago) |
|---|
-
trac/wiki/formatter.py
WikiFormatting: add some support for WikiCreole (#4356) - `**` token for bold and `//` token for italic. Note that they should be matched by themselves, i.e. one can't use `'''` to match `**` or `''` to match `//` - `[[target]]` or `[[target|label]]` TracLinks. If `target` has to contain a `|` character, it must be wrapped in a string quote, as usual with TracLinks. The content of `[[]]` can't contain the `]]` substring. Note that support for the [[http://meta.wikimedia.org/wiki/Help:Piped_link#Pipe_trick|pipe trick]] is simply "emulated" (and to some extent only), as the wiki text is not converted before save. It is consistent with the removal of the scheme we do anyway. The reverse pipe trick is not operational yet. diff --git a/trac/wiki/formatter.py b/trac/wiki/formatter.py
a b class Formatter(object): 408 408 409 409 def _bold_formatter(self, match, fullmatch): 410 410 return self.simple_tag_handler(match, '<strong>', '</strong>') 411 # should be <b> 412 413 def _bold_wc_formatter(self, match, fullmatch): 414 return self.simple_tag_handler(match, '<b>', '</b>') 415 # should be <strong> 411 416 412 417 def _italic_formatter(self, match, fullmatch): 413 418 return self.simple_tag_handler(match, '<i>', '</i>') 414 419 420 def _italic_wc_formatter(self, match, fullmatch): 421 return self.simple_tag_handler(match, '<em>', '</em>') 422 415 423 def _underline_formatter(self, match, fullmatch): 416 424 return self.simple_tag_handler(match, '<span class="underline">', 417 425 '</span>') … … class Formatter(object): 433 441 434 442 # -- Post- IWikiSyntaxProvider rules 435 443 444 # WikiCreole line brekas 445 446 def _linebreak_wc_formatter(self, match, fullmatch): 447 return '<br />' 448 436 449 # E-mails 437 450 438 451 def _email_formatter(self, match, fullmatch): … … class Formatter(object): 473 486 ns = fullmatch.group('lns') 474 487 target = self._unquote(fullmatch.group('ltgt')) 475 488 label = fullmatch.group('label') 489 return self._make_lhref_link(match, fullmatch, rel, ns, target, label) 490 491 def _make_lhref_link(self, match, fullmatch, rel, ns, target, label): 476 492 if not label: # e.g. `[http://target]` or `[wiki:target]` 477 493 if target: 478 494 if target.startswith('//'): # for `[http://target]` … … class Formatter(object): 512 528 query = '&' + query.lstrip('?') 513 529 return tag.a(label, href=path + query + fragment) 514 530 else: 515 return self._make_link(ns, target, match, label, fullmatch) 531 return self._make_link(ns or 'wiki', target or '', match, label, 532 fullmatch) 516 533 517 534 def _make_link(self, ns, target, match, label, fullmatch): 518 535 # first check for an alias defined in trac.ini … … class Formatter(object): 610 627 label = format_to_oneliner(self.env, self.context, label) 611 628 return '<span class="wikianchor" id="%s">%s</span>' % (anchor, label) 612 629 613 # WikiMacros 630 # WikiMacros or WikiCreole links 631 632 def _macrolink_formatter(self, match, fullmatch): 633 # check for a known [[macro]] 634 macro_or_link = match[2:-2] 635 fullmatch = WikiParser._macro_re.match(macro_or_link) 636 if fullmatch: 637 name = fullmatch.group('macroname') 638 args = fullmatch.group('macroargs') 639 macro = False # not a macro 640 macrolist = name[-1] == '?' 641 if name.lower() == 'br' or name == '?': 642 macro = None 643 else: 644 macro = WikiProcessor(self, (name, name[:-1])[macrolist]) 645 if macro.error: 646 macro = False 647 if macro is not False: 648 if macrolist: 649 macro = WikiProcessor(self, 'MacroList') 650 return self._macro_formatter(match, fullmatch, macro) 651 fullmatch = WikiParser._creolelink_re.match(macro_or_link) 652 return self._lhref_formatter(match, fullmatch) 614 653 615 def _macro_formatter(self, match, fullmatch ):654 def _macro_formatter(self, match, fullmatch, macro=None): 616 655 name = fullmatch.group('macroname') 617 656 if name.lower() == 'br': 618 657 return '<br />' 619 658 if name and name[-1] == '?': # Macro?() shortcut for MacroList(Macro) 620 659 args = name[:-1] or '*' 621 name = 'MacroList'622 660 else: 623 661 args = fullmatch.group('macroargs') 624 662 try: 625 macro = WikiProcessor(self, name)626 663 return macro.process(args, in_paragraph=True) 627 664 except Exception, e: 628 665 self.env.log.error('Macro %s(%s) failed: %s' % … … class OneLinerFormatter(Formatter): 1202 1239 def _table_row_sep_formatter(self, match, fullmatch): 1203 1240 return '' 1204 1241 1205 def _macro_formatter(self, match, fullmatch): 1242 def _linebreak_wc_formatter(self, match, fullmatch): 1243 return ' ' 1244 1245 def _macro_formatter(self, match, fullmatch, macro=None): 1206 1246 name = fullmatch.group('macroname') 1207 1247 if name.lower() == 'br': 1208 1248 return ' ' … … class OutlineFormatter(Formatter): 1265 1305 1266 1306 # Avoid the possible side-effects of rendering WikiProcessors 1267 1307 1268 def _macro_formatter(self, match, fullmatch ):1308 def _macro_formatter(self, match, fullmatch, macro=None): 1269 1309 return '' 1270 1310 1271 1311 def handle_code_block(self, line, startmatch=None): -
trac/wiki/parser.py
diff --git a/trac/wiki/parser.py b/trac/wiki/parser.py
a b class WikiParser(Component): 30 30 31 31 BOLDITALIC_TOKEN = "'''''" 32 32 BOLD_TOKEN = "'''" 33 BOLD_TOKEN_WIKICREOLE = r"\*\*" 33 34 ITALIC_TOKEN = "''" 35 ITALIC_TOKEN_WIKICREOLE = "//" 34 36 UNDERLINE_TOKEN = "__" 35 37 STRIKE_TOKEN = "~~" 36 38 SUBSCRIPT_TOKEN = ",," … … class WikiParser(Component): 63 65 # Font styles 64 66 r"(?P<bolditalic>!?%s)" % BOLDITALIC_TOKEN, 65 67 r"(?P<bold>!?%s)" % BOLD_TOKEN, 68 r"(?P<bold_wc>!?%s)" % BOLD_TOKEN_WIKICREOLE, 66 69 r"(?P<italic>!?%s)" % ITALIC_TOKEN, 70 r"(?P<italic_wc>!?%s)" % ITALIC_TOKEN_WIKICREOLE, 67 71 r"(?P<underline>!?%s)" % UNDERLINE_TOKEN, 68 72 r"(?P<strike>!?%s)" % STRIKE_TOKEN, 69 73 r"(?P<subscript>!?%s)" % SUBSCRIPT_TOKEN, … … class WikiParser(Component): 71 75 r"(?P<inlinecode>!?%s(?P<inline>.*?)%s)" \ 72 76 % (STARTBLOCK_TOKEN, ENDBLOCK_TOKEN), 73 77 r"(?P<inlinecode2>!?%s(?P<inline2>.*?)%s)" \ 74 % (INLINE_TOKEN, INLINE_TOKEN)] 78 % (INLINE_TOKEN, INLINE_TOKEN), 79 ] 75 80 76 81 # Rules provided by IWikiSyntaxProviders will be inserted here 77 82 78 83 _post_rules = [ 84 # WikiCreole line breaks 85 r"(?P<linebreak_wc>!?\\\\)", 79 86 # e-mails 80 87 r"(?P<email>!?%s)" % EMAIL_LOOKALIKE_PATTERN, 81 88 # <wiki:Trac bracket links> … … class WikiParser(Component): 96 103 # [=#anchor] creation 97 104 (r"(?P<anchor>!?\[=#(?P<anchorname>%s)" % XML_NAME + 98 105 "(?P<anchorlabel>\s+[^\]]*)?\])"), 99 # [[macro]] call 100 (r"(?P<macro>!?\[\[(?P<macroname>[\w/+-]+\??|\?)" 101 r"(\]\]|\((?P<macroargs>.*?)\)\]\]))"), 106 # [[macro]] call or [[WikiCreole link]] 107 (r"(?P<macrolink>!?\[\[(?:[^]]|][^]])*\]\])"), 102 108 # == heading == #hanchor 103 109 r"(?P<heading>^\s*(?P<hdepth>={1,6})\s(?P<htext>.*?)" 104 110 r"(?P<hanchor>#%s)?\s*$)" % XML_NAME, … … class WikiParser(Component): 125 131 _startblock_re = re.compile(r"\s*%s(?:%s|\s*$)" % 126 132 (STARTBLOCK, PROCESSOR)) 127 133 _processor_param_re = re.compile(PROCESSOR_PARAM) 128 _anchor_re = re.compile('[^\w:.-]+', re.UNICODE) 134 _anchor_re = re.compile(r'[^\w:.-]+', re.UNICODE) 135 136 _macro_re = re.compile(r''' 137 (?P<macroname> [\w/+-]+ \?? | \? ) # macro, macro? or ? 138 (?: \( (?P<macroargs> .*? ) \) )? $ # optional arguments within () 139 ''', re.VERBOSE) 140 141 _creolelink_re = re.compile(r''' 142 (?: 143 (?P<rel> %(rel)s ) # rel is "./..." or "/..." 144 | (?: (?P<lns> %(scheme)s ) : )? # lns is the optional "scheme:" 145 (?P<ltgt> # ltgt is the optional target 146 %(scheme)s : (?:%(quoted)s) # - "scheme:'...quoted..'" 147 | %(quoted)s # - "'...quoted...'" 148 | [^|]+ # - anything but a '|' 149 )? 150 ) 151 \s* (?: \| (?P<label> .* ) )? # optional label after a '|' 152 153 ''' % {'rel': LHREF_RELATIVE_TARGET, 154 'scheme': LINK_SCHEME, 155 'quoted': QUOTED_STRING}, re.VERBOSE) 129 156 130 157 def __init__(self): 131 158 self._compiled_rules = None -
trac/wiki/tests/wiki-tests.txt
diff --git a/trac/wiki/tests/wiki-tests.txt b/trac/wiki/tests/wiki-tests.txt
a b This should be '''''bold and italic''''' 9 9 This should be <strong><i>bold and italic</i></strong> 10 10 </p> 11 11 ------------------------------ 12 ============================== Multiline bold italic markup (WikiCreole) 13 **//bold 14 italic (//not italic//) 15 multiline//** 16 ------------------------------ 17 <p> 18 <b><em>bold 19 italic (</em>not italic<em>) 20 multiline</em></b> 21 </p> 22 ------------------------------ 12 23 ============================== Problematic markup: comma-separated list with a time + bold markup 13 24 23:59,'''test''',123 14 25 ------------------------------ … … rfc-2396.compatible://link 433 444 <a class="ext-link" href="rfc-2396.compatible://link"><span class="icon"> </span>RFC 2396</a> 434 445 </p> 435 446 ------------------------------ 447 ============================== WikiCreole style for the above examples 448 [[link:WikiStart| Foo]] [[http://www.edgewall.com/|Edgewall]] 449 450 [[link:Foo Bar|Foo Bar]] [[link:Foo Bar#baz|Foo Bar]] 451 452 [[Foo Bar]] [[Foo Bar|Fu Bar]] [[Foo Bar#baz|Foo Bar]] 453 454 [[link:Argv|"*argv[] versus **argv"]] 455 456 [[link:test|"test.txt", line 123]] 457 458 [[link:pl/de|%de]] 459 460 i.e. [[mailto:cboos@neuf.fr|me]] 461 462 [[th:]] 463 [[th:|Trac Hacks]] 464 465 [[svn+ssh://secureserver.org|SVN link]] 466 [[rfc-2396.compatible://link|RFC 2396]] 467 ------------------------------ 468 <p> 469 <a class="text resolver" href="/stuff/WikiStart"> Foo</a> <a class="ext-link" href="http://www.edgewall.com/"><span class="icon"> </span>Edgewall</a> 470 </p> 471 <p> 472 <a class="text resolver" href="/stuff/Foo%20Bar">Foo Bar</a> <a class="text resolver" href="/stuff/Foo%20Bar%23baz">Foo Bar</a> 473 </p> 474 <p> 475 <a class="missing wiki" href="/wiki/Foo%20Bar" rel="nofollow">Foo Bar?</a> <a class="missing wiki" href="/wiki/Foo%20Bar" rel="nofollow">Fu Bar?</a> <a class="missing wiki" href="/wiki/Foo%20Bar#baz" rel="nofollow">Foo Bar?</a> 476 </p> 477 <p> 478 <a class="text resolver" href="/stuff/Argv">*argv[] versus **argv</a> 479 </p> 480 <p> 481 <a class="text resolver" href="/stuff/test">"test.txt", line 123</a> 482 </p> 483 <p> 484 <a class="text resolver" href="/stuff/pl/de">%de</a> 485 </p> 486 <p> 487 i.e. <a class="mail-link" href="mailto:cboos@neuf.fr"><span class="icon"> </span>me</a> 488 </p> 489 <p> 490 <a class="ext-link" href="http://trac-hacks.org/intertrac/" title="Trac Hacks"><span class="icon"> </span>th</a> 491 <a class="ext-link" href="http://trac-hacks.org/intertrac/" title="Trac Hacks"><span class="icon"> </span>Trac Hacks</a> 492 </p> 493 <p> 494 <a class="ext-link" href="svn+ssh://secureserver.org"><span class="icon"> </span>SVN link</a> 495 <a class="ext-link" href="rfc-2396.compatible://link"><span class="icon"> </span>RFC 2396</a> 496 </p> 497 ------------------------------ 498 ============================== More WikiCreole examples 499 [[coffeehouse setup|How to set up a coffee house]] 500 501 [[link:Template]] 502 [[link:Template|]] 503 504 [[trac:wiki:Pipe (computing)|]] 505 [[trac:wiki:Pipe (computing)|]] 506 507 [[|b]] (might change to relative) 508 ------------------------------ 509 <p> 510 <a class="missing wiki" href="/wiki/coffeehouse%20setup" rel="nofollow">How to set up a coffee house?</a> 511 </p> 512 <p> 513 <a class="text resolver" href="/stuff/Template">Template</a> 514 <a class="text resolver" href="/stuff/Template">Template</a> 515 </p> 516 <p> 517 <a class="ext-link" href="http://trac.edgewall.org/intertrac/wiki%3APipe%20%28computing%29" title="wiki:Pipe (computing) in Trac's Trac"><span class="icon"> </span>trac:wiki:Pipe (computing)</a> 518 <a class="ext-link" href="http://trac.edgewall.org/intertrac/wiki%3APipe%20%28computing%29" title="wiki:Pipe (computing) in Trac's Trac"><span class="icon"> </span>trac:wiki:Pipe (computing)</a> 519 </p> 520 <p> 521 <a class="wiki" href="/wiki/WikiStart">b</a> (might change to relative) 522 </p> 523 ------------------------------ 436 524 ============================== Link resolver counter examples 437 525 Test:[[BR]] There should be a 438 526 line break … … Hello, Hello World, args = hej hopp 862 950 </p> 863 951 ------------------------------ 864 952 Hello, [[HelloWorld(...)]] 865 ============================== Bad macro call 953 ============================== Bad macro call, but valid WikiCreole link 866 954 [[HelloWorld(hej hopp) ]] # This shouldnt executed as macro since it contain whitespace between ) and ] 867 955 ------------------------------ 868 956 <p> 869 [[<a class="missing wiki" href="/wiki/HelloWorld" rel="nofollow">HelloWorld?</a>(hej hopp) ]]# This shouldnt executed as macro since it contain whitespace between ) and ]957 <a class="missing wiki" href="/wiki/HelloWorld%28hej%20hopp%29%20" rel="nofollow">HelloWorld(hej hopp) ?</a> # This shouldnt executed as macro since it contain whitespace between ) and ] 870 958 </p> 871 959 ------------------------------ 872 [[<a class="missing wiki" href="/wiki/HelloWorld" rel="nofollow">HelloWorld?</a>(hej hopp) ]]# This shouldnt executed as macro since it contain whitespace between ) and ]960 <a class="missing wiki" href="/wiki/HelloWorld%28hej%20hopp%29%20" rel="nofollow">HelloWorld(hej hopp) ?</a> # This shouldnt executed as macro since it contain whitespace between ) and ] 873 961 ============================== Another bad macro call 874 962 [[HelloWorld(hej hopp))]] # Extra right brace and still executed 875 963 ------------------------------ … … Line break <br /> another line<br />last 967 1055 </p> 968 1056 ------------------------------ 969 1057 Line break another line last line 1058 ============================== WikiCreole line break 1059 Line break \\ another line\\last line 1060 ------------------------------ 1061 <p> 1062 Line break <br /> another line<br />last line 1063 </p> 1064 ------------------------------ 1065 Line break another line last line 970 1066 ============================== Comment wiki processor 971 1067 Test comment blocks 972 1068 {{{
