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/trac/wiki/formatter.py
+++ b/trac/wiki/formatter.py
@@ -408,10 +408,18 @@ class Formatter(object):
 
     def _bold_formatter(self, match, fullmatch):
         return self.simple_tag_handler(match, '<strong>', '</strong>')
+    # should be <b>
+
+    def _bold_wc_formatter(self, match, fullmatch):
+        return self.simple_tag_handler(match, '<b>', '</b>')
+    # should be <strong>
 
     def _italic_formatter(self, match, fullmatch):
         return self.simple_tag_handler(match, '<i>', '</i>')
 
+    def _italic_wc_formatter(self, match, fullmatch):
+        return self.simple_tag_handler(match, '<em>', '</em>')
+
     def _underline_formatter(self, match, fullmatch):
         return self.simple_tag_handler(match, '<span class="underline">',
                                        '</span>')
@@ -473,6 +481,9 @@ class Formatter(object):
         ns = fullmatch.group('lns')
         target = self._unquote(fullmatch.group('ltgt'))
         label = fullmatch.group('label')
+        return self._make_lhref_link(match, fullmatch, rel, ns, target, label)
+
+    def _make_lhref_link(self, match, fullmatch, rel, ns, target, label):
         if not label: # e.g. `[http://target]` or `[wiki:target]`
             if target:
                 if target.startswith('//'):     # for `[http://target]`
@@ -512,7 +523,8 @@ class Formatter(object):
                     query = '&' + query.lstrip('?')
             return tag.a(label, href=path + query + fragment)
         else:
-            return self._make_link(ns, target, match, label, fullmatch)
+            return self._make_link(ns or 'wiki', target or '', match, label,
+                                   fullmatch)
 
     def _make_link(self, ns, target, match, label, fullmatch):
         # first check for an alias defined in trac.ini
@@ -610,19 +622,39 @@ class Formatter(object):
             label = format_to_oneliner(self.env, self.context, label)
         return '<span class="wikianchor" id="%s">%s</span>' % (anchor, label)
 
-    # WikiMacros
+    # WikiMacros or WikiCreole links
+
+    def _macrolink_formatter(self, match, fullmatch):
+        # check for a known [[macro]]
+        macro_or_link = match[2:-2]
+        fullmatch = WikiParser._macro_re.match(macro_or_link)
+        if fullmatch:
+            name = fullmatch.group('macroname')
+            args = fullmatch.group('macroargs')
+            macro = False # not a macro
+            macrolist = name[-1] == '?'
+            if name.lower() == 'br' or name == '?':
+                macro = None
+            else:
+                macro = WikiProcessor(self, (name, name[:-1])[macrolist])
+                if macro.error:
+                    macro = False
+            if macro is not False:
+                if macrolist:
+                    macro = WikiProcessor(self, 'MacroList')
+                return self._macro_formatter(match, fullmatch, macro)
+        fullmatch = WikiParser._creolelink_re.match(macro_or_link)
+        return self._lhref_formatter(match, fullmatch)
     
-    def _macro_formatter(self, match, fullmatch):
+    def _macro_formatter(self, match, fullmatch, macro=None):
         name = fullmatch.group('macroname')
         if name.lower() == 'br':
             return '<br />'
         if name and name[-1] == '?': # Macro?() shortcut for MacroList(Macro)
             args = name[:-1] or '*'
-            name = 'MacroList'
         else:
             args = fullmatch.group('macroargs')
         try:
-            macro = WikiProcessor(self, name)
             return macro.process(args, in_paragraph=True)
         except Exception, e:
             self.env.log.error('Macro %s(%s) failed: %s' % 
@@ -1202,7 +1234,7 @@ class OneLinerFormatter(Formatter):
     def _table_row_sep_formatter(self, match, fullmatch):
         return ''
 
-    def _macro_formatter(self, match, fullmatch):
+    def _macro_formatter(self, match, fullmatch, macro=None):
         name = fullmatch.group('macroname')
         if name.lower() == 'br':
             return ' '
@@ -1265,7 +1297,7 @@ class OutlineFormatter(Formatter):
 
     # Avoid the possible side-effects of rendering WikiProcessors
 
-    def _macro_formatter(self, match, fullmatch):
+    def _macro_formatter(self, match, fullmatch, macro=None):
         return ''
 
     def handle_code_block(self, line, startmatch=None):
diff --git a/trac/wiki/parser.py b/trac/wiki/parser.py
--- a/trac/wiki/parser.py
+++ b/trac/wiki/parser.py
@@ -30,7 +30,9 @@ class WikiParser(Component):
 
     BOLDITALIC_TOKEN = "'''''"
     BOLD_TOKEN = "'''"
+    BOLD_TOKEN_WIKICREOLE = r"\*\*"
     ITALIC_TOKEN = "''"
+    ITALIC_TOKEN_WIKICREOLE = "//"
     UNDERLINE_TOKEN = "__"
     STRIKE_TOKEN = "~~"
     SUBSCRIPT_TOKEN = ",,"
@@ -63,7 +65,9 @@ class WikiParser(Component):
         # Font styles
         r"(?P<bolditalic>!?%s)" % BOLDITALIC_TOKEN,
         r"(?P<bold>!?%s)" % BOLD_TOKEN,
+        r"(?P<bold_wc>!?%s)" % BOLD_TOKEN_WIKICREOLE,        
         r"(?P<italic>!?%s)" % ITALIC_TOKEN,
+        r"(?P<italic_wc>!?%s)" % ITALIC_TOKEN_WIKICREOLE,        
         r"(?P<underline>!?%s)" % UNDERLINE_TOKEN,
         r"(?P<strike>!?%s)" % STRIKE_TOKEN,
         r"(?P<subscript>!?%s)" % SUBSCRIPT_TOKEN,
@@ -71,7 +75,8 @@ class WikiParser(Component):
         r"(?P<inlinecode>!?%s(?P<inline>.*?)%s)" \
         % (STARTBLOCK_TOKEN, ENDBLOCK_TOKEN),
         r"(?P<inlinecode2>!?%s(?P<inline2>.*?)%s)" \
-        % (INLINE_TOKEN, INLINE_TOKEN)]
+        % (INLINE_TOKEN, INLINE_TOKEN),
+        ]
 
     # Rules provided by IWikiSyntaxProviders will be inserted here
 
@@ -96,9 +101,8 @@ class WikiParser(Component):
         # [=#anchor] creation
         (r"(?P<anchor>!?\[=#(?P<anchorname>%s)" % XML_NAME +
          "(?P<anchorlabel>\s+[^\]]*)?\])"),
-        # [[macro]] call
-        (r"(?P<macro>!?\[\[(?P<macroname>[\w/+-]+\??|\?)"
-         r"(\]\]|\((?P<macroargs>.*?)\)\]\]))"),
+        # [[macro]] call or [[WikiCreole link]]
+        (r"(?P<macrolink>!?\[\[(?:[^]]|][^]])*\]\])"),
         # == heading == #hanchor
         r"(?P<heading>^\s*(?P<hdepth>={1,6})\s(?P<htext>.*?)"
         r"(?P<hanchor>#%s)?\s*$)" % XML_NAME,
@@ -125,7 +129,28 @@ class WikiParser(Component):
     _startblock_re = re.compile(r"\s*%s(?:%s|\s*$)" %
                                 (STARTBLOCK, PROCESSOR))
     _processor_param_re = re.compile(PROCESSOR_PARAM)
-    _anchor_re = re.compile('[^\w:.-]+', re.UNICODE)
+    _anchor_re = re.compile(r'[^\w:.-]+', re.UNICODE)
+
+    _macro_re = re.compile(r'''
+        (?P<macroname> [\w/+-]+ \?? | \? )     # macro, macro? or ?
+          (?: \( (?P<macroargs> .*? ) \) )? $  # optional arguments within ()
+    ''', re.VERBOSE)
+
+    _creolelink_re = re.compile(r'''
+        (?:
+          (?P<rel> %(rel)s )                # rel is "./..." or "/..."
+        | (?: (?P<lns> %(scheme)s ) : )?    # lns is the optional "scheme:"
+            (?P<ltgt>                       # ltgt is the optional target
+              %(scheme)s : (?:%(quoted)s)   #   - "scheme:'...quoted..'"
+            | %(quoted)s                    #   - "'...quoted...'"
+            | [^|]+                         #   - anything but a '|'
+            )?
+        )
+        \s* (?: \| (?P<label> .* ) )?       # optional label after a '|'
+
+        ''' % {'rel': LHREF_RELATIVE_TARGET,
+               'scheme': LINK_SCHEME,
+               'quoted': QUOTED_STRING}, re.VERBOSE)
 
     def __init__(self):
         self._compiled_rules = None
diff --git a/trac/wiki/tests/wiki-tests.txt b/trac/wiki/tests/wiki-tests.txt
--- a/trac/wiki/tests/wiki-tests.txt
+++ b/trac/wiki/tests/wiki-tests.txt
@@ -9,6 +9,17 @@ This should be '''''bold and italic'''''
 This should be <strong><i>bold and italic</i></strong>
 </p>
 ------------------------------
+============================== Multiline bold italic markup (WikiCreole)
+**//bold
+italic (//not italic//)
+multiline//**
+------------------------------
+<p>
+<b><em>bold
+italic (</em>not italic<em>)
+multiline</em></b>
+</p>
+------------------------------
 ============================== Problematic markup: comma-separated list with a time + bold markup
 23:59,'''test''',123
 ------------------------------
@@ -433,6 +444,83 @@ rfc-2396.compatible://link
 <a class="ext-link" href="rfc-2396.compatible://link"><span class="icon"> </span>RFC 2396</a>
 </p>
 ------------------------------
+============================== WikiCreole style for the above examples
+[[link:WikiStart| Foo]] [[http://www.edgewall.com/|Edgewall]]
+
+[[link:Foo Bar|Foo Bar]] [[link:Foo Bar#baz|Foo Bar]]
+
+[[Foo Bar]] [[Foo Bar|Fu Bar]] [[Foo Bar#baz|Foo Bar]]
+
+[[link:Argv|"*argv[] versus **argv"]]
+
+[[link:test|"test.txt", line 123]]
+
+[[link:pl/de|%de]]
+
+i.e. [[mailto:cboos@neuf.fr|me]]
+
+[[th:]]
+[[th:|Trac Hacks]]
+
+[[svn+ssh://secureserver.org|SVN link]]
+[[rfc-2396.compatible://link|RFC 2396]]
+------------------------------
+<p>
+<a class="text resolver" href="/stuff/WikiStart"> Foo</a> <a class="ext-link" href="http://www.edgewall.com/"><span class="icon"> </span>Edgewall</a>
+</p>
+<p>
+<a class="text resolver" href="/stuff/Foo%20Bar">Foo Bar</a> <a class="text resolver" href="/stuff/Foo%20Bar%23baz">Foo Bar</a>
+</p>
+<p>
+<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>
+</p>
+<p>
+<a class="text resolver" href="/stuff/Argv">*argv[] versus **argv</a>
+</p>
+<p>
+<a class="text resolver" href="/stuff/test">"test.txt", line 123</a>
+</p>
+<p>
+<a class="text resolver" href="/stuff/pl/de">%de</a>
+</p>
+<p>
+i.e. <a class="mail-link" href="mailto:cboos@neuf.fr"><span class="icon"> </span>me</a>
+</p>
+<p>
+<a class="ext-link" href="http://trac-hacks.org/intertrac/" title="Trac Hacks"><span class="icon"> </span>th</a>
+<a class="ext-link" href="http://trac-hacks.org/intertrac/" title="Trac Hacks"><span class="icon"> </span>Trac Hacks</a>
+</p>
+<p>
+<a class="ext-link" href="svn+ssh://secureserver.org"><span class="icon"> </span>SVN link</a>
+<a class="ext-link" href="rfc-2396.compatible://link"><span class="icon"> </span>RFC 2396</a>
+</p>
+------------------------------
+============================== More WikiCreole examples 
+[[coffeehouse setup|How to set up a coffee house]]
+
+[[link:Template]]
+[[link:Template|]]
+
+[[trac:wiki:Pipe (computing)|]]
+[[trac:wiki:Pipe (computing)|]]
+
+[[|b]] (might change to relative)
+------------------------------
+<p>
+<a class="missing wiki" href="/wiki/coffeehouse%20setup" rel="nofollow">How to set up a coffee house?</a>
+</p>
+<p>
+<a class="text resolver" href="/stuff/Template">Template</a>
+<a class="text resolver" href="/stuff/Template">Template</a>
+</p>
+<p>
+<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>
+<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>
+</p>
+<p>
+<a class="wiki" href="/wiki/WikiStart">b</a> (might change to relative)
+</p>
+------------------------------
 ============================== Link resolver counter examples
 Test:[[BR]] There should be a
 line break
@@ -862,14 +950,14 @@ Hello, Hello World, args = hej hopp
 </p>
 ------------------------------
 Hello, [[HelloWorld(...)]]
-============================== Bad macro call
+============================== Bad macro call, but valid WikiCreole link
 [[HelloWorld(hej hopp) ]] # This shouldnt executed as macro since it contain whitespace between ) and ]
 ------------------------------
 <p>
-[[<a class="missing wiki" href="/wiki/HelloWorld" rel="nofollow">HelloWorld?</a>(hej hopp) ]] # This shouldnt executed as macro since it contain whitespace between ) and ]
+<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 ]
 </p>
 ------------------------------
-[[<a class="missing wiki" href="/wiki/HelloWorld" rel="nofollow">HelloWorld?</a>(hej hopp) ]] # This shouldnt executed as macro since it contain whitespace between ) and ]
+<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 ]
 ============================== Another bad macro call
 [[HelloWorld(hej hopp))]] # Extra right brace and still executed
 ------------------------------

