Edgewall Software

Ticket #4356: trac_wiki_creole-r9337.2.patch

File trac_wiki_creole-r9337.2.patch, 14.5 KB (added by cboos, 2 years ago)

new version, adds support for forced line breaks (\\)

  • 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): 
    408408 
    409409    def _bold_formatter(self, match, fullmatch): 
    410410        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> 
    411416 
    412417    def _italic_formatter(self, match, fullmatch): 
    413418        return self.simple_tag_handler(match, '<i>', '</i>') 
    414419 
     420    def _italic_wc_formatter(self, match, fullmatch): 
     421        return self.simple_tag_handler(match, '<em>', '</em>') 
     422 
    415423    def _underline_formatter(self, match, fullmatch): 
    416424        return self.simple_tag_handler(match, '<span class="underline">', 
    417425                                       '</span>') 
    class Formatter(object): 
    433441 
    434442    # -- Post- IWikiSyntaxProvider rules 
    435443 
     444    # WikiCreole line brekas 
     445 
     446    def _linebreak_wc_formatter(self, match, fullmatch): 
     447        return '<br />' 
     448 
    436449    # E-mails 
    437450 
    438451    def _email_formatter(self, match, fullmatch): 
    class Formatter(object): 
    473486        ns = fullmatch.group('lns') 
    474487        target = self._unquote(fullmatch.group('ltgt')) 
    475488        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): 
    476492        if not label: # e.g. `[http://target]` or `[wiki:target]` 
    477493            if target: 
    478494                if target.startswith('//'):     # for `[http://target]` 
    class Formatter(object): 
    512528                    query = '&' + query.lstrip('?') 
    513529            return tag.a(label, href=path + query + fragment) 
    514530        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) 
    516533 
    517534    def _make_link(self, ns, target, match, label, fullmatch): 
    518535        # first check for an alias defined in trac.ini 
    class Formatter(object): 
    610627            label = format_to_oneliner(self.env, self.context, label) 
    611628        return '<span class="wikianchor" id="%s">%s</span>' % (anchor, label) 
    612629 
    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) 
    614653     
    615     def _macro_formatter(self, match, fullmatch): 
     654    def _macro_formatter(self, match, fullmatch, macro=None): 
    616655        name = fullmatch.group('macroname') 
    617656        if name.lower() == 'br': 
    618657            return '<br />' 
    619658        if name and name[-1] == '?': # Macro?() shortcut for MacroList(Macro) 
    620659            args = name[:-1] or '*' 
    621             name = 'MacroList' 
    622660        else: 
    623661            args = fullmatch.group('macroargs') 
    624662        try: 
    625             macro = WikiProcessor(self, name) 
    626663            return macro.process(args, in_paragraph=True) 
    627664        except Exception, e: 
    628665            self.env.log.error('Macro %s(%s) failed: %s' %  
    class OneLinerFormatter(Formatter): 
    12021239    def _table_row_sep_formatter(self, match, fullmatch): 
    12031240        return '' 
    12041241 
    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): 
    12061246        name = fullmatch.group('macroname') 
    12071247        if name.lower() == 'br': 
    12081248            return ' ' 
    class OutlineFormatter(Formatter): 
    12651305 
    12661306    # Avoid the possible side-effects of rendering WikiProcessors 
    12671307 
    1268     def _macro_formatter(self, match, fullmatch): 
     1308    def _macro_formatter(self, match, fullmatch, macro=None): 
    12691309        return '' 
    12701310 
    12711311    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): 
    3030 
    3131    BOLDITALIC_TOKEN = "'''''" 
    3232    BOLD_TOKEN = "'''" 
     33    BOLD_TOKEN_WIKICREOLE = r"\*\*" 
    3334    ITALIC_TOKEN = "''" 
     35    ITALIC_TOKEN_WIKICREOLE = "//" 
    3436    UNDERLINE_TOKEN = "__" 
    3537    STRIKE_TOKEN = "~~" 
    3638    SUBSCRIPT_TOKEN = ",," 
    class WikiParser(Component): 
    6365        # Font styles 
    6466        r"(?P<bolditalic>!?%s)" % BOLDITALIC_TOKEN, 
    6567        r"(?P<bold>!?%s)" % BOLD_TOKEN, 
     68        r"(?P<bold_wc>!?%s)" % BOLD_TOKEN_WIKICREOLE,         
    6669        r"(?P<italic>!?%s)" % ITALIC_TOKEN, 
     70        r"(?P<italic_wc>!?%s)" % ITALIC_TOKEN_WIKICREOLE,         
    6771        r"(?P<underline>!?%s)" % UNDERLINE_TOKEN, 
    6872        r"(?P<strike>!?%s)" % STRIKE_TOKEN, 
    6973        r"(?P<subscript>!?%s)" % SUBSCRIPT_TOKEN, 
    class WikiParser(Component): 
    7175        r"(?P<inlinecode>!?%s(?P<inline>.*?)%s)" \ 
    7276        % (STARTBLOCK_TOKEN, ENDBLOCK_TOKEN), 
    7377        r"(?P<inlinecode2>!?%s(?P<inline2>.*?)%s)" \ 
    74         % (INLINE_TOKEN, INLINE_TOKEN)] 
     78        % (INLINE_TOKEN, INLINE_TOKEN), 
     79        ] 
    7580 
    7681    # Rules provided by IWikiSyntaxProviders will be inserted here 
    7782 
    7883    _post_rules = [ 
     84        # WikiCreole line breaks 
     85        r"(?P<linebreak_wc>!?\\\\)",  
    7986        # e-mails 
    8087        r"(?P<email>!?%s)" % EMAIL_LOOKALIKE_PATTERN, 
    8188        # <wiki:Trac bracket links> 
    class WikiParser(Component): 
    96103        # [=#anchor] creation 
    97104        (r"(?P<anchor>!?\[=#(?P<anchorname>%s)" % XML_NAME + 
    98105         "(?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>!?\[\[(?:[^]]|][^]])*\]\])"), 
    102108        # == heading == #hanchor 
    103109        r"(?P<heading>^\s*(?P<hdepth>={1,6})\s(?P<htext>.*?)" 
    104110        r"(?P<hanchor>#%s)?\s*$)" % XML_NAME, 
    class WikiParser(Component): 
    125131    _startblock_re = re.compile(r"\s*%s(?:%s|\s*$)" % 
    126132                                (STARTBLOCK, PROCESSOR)) 
    127133    _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) 
    129156 
    130157    def __init__(self): 
    131158        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''''' 
    99This should be <strong><i>bold and italic</i></strong> 
    1010</p> 
    1111------------------------------ 
     12============================== Multiline bold italic markup (WikiCreole) 
     13**//bold 
     14italic (//not italic//) 
     15multiline//** 
     16------------------------------ 
     17<p> 
     18<b><em>bold 
     19italic (</em>not italic<em>) 
     20multiline</em></b> 
     21</p> 
     22------------------------------ 
    1223============================== Problematic markup: comma-separated list with a time + bold markup 
    132423:59,'''test''',123 
    1425------------------------------ 
    rfc-2396.compatible://link 
    433444<a class="ext-link" href="rfc-2396.compatible://link"><span class="icon"> </span>RFC 2396</a> 
    434445</p> 
    435446------------------------------ 
     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 
     460i.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> 
     487i.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------------------------------ 
    436524============================== Link resolver counter examples 
    437525Test:[[BR]] There should be a 
    438526line break 
    Hello, Hello World, args = hej hopp 
    862950</p> 
    863951------------------------------ 
    864952Hello, [[HelloWorld(...)]] 
    865 ============================== Bad macro call 
     953============================== Bad macro call, but valid WikiCreole link 
    866954[[HelloWorld(hej hopp) ]] # This shouldnt executed as macro since it contain whitespace between ) and ] 
    867955------------------------------ 
    868956<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 ] 
    870958</p> 
    871959------------------------------ 
    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 ] 
    873961============================== Another bad macro call 
    874962[[HelloWorld(hej hopp))]] # Extra right brace and still executed 
    875963------------------------------ 
    Line break <br /> another line<br />last 
    9671055</p> 
    9681056------------------------------ 
    9691057Line break   another line last line 
     1058============================== WikiCreole line break 
     1059Line break \\ another line\\last line 
     1060------------------------------ 
     1061<p> 
     1062Line break <br /> another line<br />last line 
     1063</p> 
     1064------------------------------ 
     1065Line break   another line last line 
    9701066============================== Comment wiki processor 
    9711067Test comment blocks 
    9721068{{{