changeset 2743:7bfe80df6772

merge main
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Tue, 21 Aug 2007 15:47:56 +0200
parents 0f16bcbc0344 (diff) c6b5c2d813b6 (current diff)
children e931f45fec3a
files MoinMoin/_tests/test_wikiutil.py MoinMoin/wikiutil.py
diffstat 48 files changed, 2270 insertions(+), 862 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/PageEditor.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/PageEditor.py	Tue Aug 21 15:47:56 2007 +0200
@@ -302,7 +302,7 @@
                     loadable_draft = True
                     page_rev = rev
                     draft_timestamp_str = request.user.getFormattedDateTime(draft_timestamp)
-                    draft_message = _(u"'''[[BR]]Your draft based on revision %(draft_rev)d (saved %(draft_timestamp_str)s) can be loaded instead of the current revision %(page_rev)d by using the load draft button - in case you lost your last edit somehow without saving it.''' A draft gets saved for you when you do a preview, cancel an edit or unsuccessfully save.") % locals()
+                    draft_message = _(u"'''<<BR>>Your draft based on revision %(draft_rev)d (saved %(draft_timestamp_str)s) can be loaded instead of the current revision %(page_rev)d by using the load draft button - in case you lost your last edit somehow without saving it.''' A draft gets saved for you when you do a preview, cancel an edit or unsuccessfully save.") % locals()
 
         # Setup status message
         status = [kw.get('msg', ''), conflict_msg, edit_lock_message, draft_message]
@@ -750,17 +750,17 @@
         signature = u.signature()
         variables = {
             'PAGE': self.page_name,
-            'TIME': "[[DateTime(%s)]]" % now,
-            'DATE': "[[Date(%s)]]" % now,
+            'TIME': "<<DateTime(%s)>>" % now,
+            'DATE': "<<Date(%s)>>" % now,
             'ME': u.name,
             'USERNAME': signature,
             'USER': "-- %s" % signature,
-            'SIG': "-- %s [[DateTime(%s)]]" % (signature, now),
+            'SIG': "-- %s <<DateTime(%s)>>" % (signature, now),
         }
 
         if u.valid and u.name:
             if u.email:
-                variables['MAILTO'] = "[[MailTo(%s)]]" % u.email
+                variables['MAILTO'] = "<<MailTo(%s)>>" % u.email
             # Users can define their own variables via
             # UserHomepage/MyDict, which override the default variables.
             userDictPage = u.name + "/MyDict"
@@ -1207,9 +1207,9 @@
                 # warn user about existing lock
 
                 result = 1, _(
-"""This page was opened for editing or last previewed at %(timestamp)s by %(owner)s.[[BR]]
+"""This page was opened for editing or last previewed at %(timestamp)s by %(owner)s.<<BR>>
 '''You should ''refrain from editing'' this page for at least another %(mins_valid)d minute(s),
-to avoid editing conflicts.'''[[BR]]
+to avoid editing conflicts.'''<<BR>>
 To leave the editor, press the Cancel button.""") % {
                     'timestamp': timestamp, 'owner': owner, 'mins_valid': mins_valid}
 
--- a/MoinMoin/PageGraphicalEditor.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/PageGraphicalEditor.py	Tue Aug 21 15:47:56 2007 +0200
@@ -193,7 +193,7 @@
                     loadable_draft = True
                     page_rev = rev
                     draft_timestamp_str = request.user.getFormattedDateTime(draft_timestamp)
-                    draft_message = _(u"'''[[BR]]Your draft based on revision %(draft_rev)d (saved %(draft_timestamp_str)s) can be loaded instead of the current revision %(page_rev)d by using the load draft button - in case you lost your last edit somehow without saving it.''' A draft gets saved for you when you do a preview, cancel an edit or unsuccessfully save.") % locals()
+                    draft_message = _(u"'''<<BR>>Your draft based on revision %(draft_rev)d (saved %(draft_timestamp_str)s) can be loaded instead of the current revision %(page_rev)d by using the load draft button - in case you lost your last edit somehow without saving it.''' A draft gets saved for you when you do a preview, cancel an edit or unsuccessfully save.") % locals()
 
         # Setup status message
         status = [kw.get('msg', ''), conflict_msg, edit_lock_message, draft_message]
--- a/MoinMoin/_tests/_test_template.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/_tests/_test_template.py	Tue Aug 21 15:47:56 2007 +0200
@@ -42,7 +42,7 @@
     """
     _tests = (
         # description,  test,            expected
-        ('Line break',  '[[BR]]',        '<br>'),
+        ('Line break',  '<<BR>>',        '<br>'),
     )
 
     def setup_class(cls):
--- a/MoinMoin/_tests/test_PageEditor.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/_tests/test_PageEditor.py	Tue Aug 21 15:47:56 2007 +0200
@@ -75,7 +75,7 @@
         """ PageEditor: expand @USERNAME@ extended name - enabled """
         try:
             config = self.TestConfig()
-            self.assertEqual(self.expand(), u'["%s"]' % self.name)
+            self.assertEqual(self.expand(), u'[[%s]]' % self.name)
         finally:
             del config
 
@@ -100,7 +100,7 @@
 
     def testMailto(self):
         """ PageEditor: expand @MAILTO@ """
-        self.assertEqual(self.expand(), u'[[MailTo(%s)]]' % self.email)
+        self.assertEqual(self.expand(), u'<<MailTo(%s)>>' % self.email)
 
 
 class TestExpandPrivateVariables(TestExpandUserName):
--- a/MoinMoin/_tests/test_wikiutil.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/_tests/test_wikiutil.py	Tue Aug 21 15:47:56 2007 +0200
@@ -66,37 +66,16 @@
             assert wikiutil.clean_input(instr) == outstr
 
 
-class TestNameQuoting:
-    tests = [(u"", u'""'), # empty
-             (u"test", u'"test"'), # nothing special
-             (u"Sarah O'Connor", u"\"Sarah O'Connor\""),
-             (u'Just "something" quoted', u'"Just ""something"" quoted"'),
-            ]
-    def testQuoteName(self):
-        for name, qname in self.tests:
-            assert wikiutil.quoteName(name) == qname
-
-    def testUnquoteName(self):
-        for name, qname in self.tests:
-            assert wikiutil.unquoteName(qname) == name
-
-
 class TestInterWiki:
     def testSplitWiki(self):
-        tests = [('SomePage', ('Self', 'SomePage', '')),
-                 ('OtherWiki:OtherPage', ('OtherWiki', 'OtherPage', '')),
-                 ('MoinMoin:"Page with blanks" link title', ("MoinMoin", "Page with blanks", "link title")),
-                 ('MoinMoin:"Page with blanks"link title', ("MoinMoin", "Page with blanks", "link title")),
-                 ('MoinMoin:"Page with blanks"', ("MoinMoin", "Page with blanks", "")),
-                 ('MoinMoin:"Page with ""quote""" link title', ("MoinMoin", 'Page with "quote"', "link title")),
-                 ('MoinMoin:"Page with """"double-quote"""link title', ("MoinMoin", 'Page with ""double-quote"', "link title")),
-                 ('MoinMoin:"""starts with quote"link title', ("MoinMoin", '"starts with quote', "link title")),
-                 ('MoinMoin:"ends with quote"""link title', ("MoinMoin", 'ends with quote"', "link title")),
-                 ('MoinMoin:"""page with quotes around"""link title', ("MoinMoin", '"page with quotes around"', "link title")),
-                 ('attachment:"filename with blanks.txt" other title', ("attachment", "filename with blanks.txt", "other title")),
+        tests = [('SomePage', ('Self', 'SomePage')),
+                 ('OtherWiki:OtherPage', ('OtherWiki', 'OtherPage')),
+                 (':OtherPage', ('', 'OtherPage')),
+                 # broken ('/OtherPage', ('Self', '/OtherPage')),
+                 # wrong interpretation ('MainPage/OtherPage', ('Self', 'MainPage/OtherPage')),
                 ]
-        for markup, (wikiname, pagename, linktext) in tests:
-            assert wikiutil.split_wiki(markup) == (wikiname, pagename, linktext)
+        for markup, (wikiname, pagename) in tests:
+            assert wikiutil.split_wiki(markup) == (wikiname, pagename)
 
     def testJoinWiki(self):
         tests = [(('http://example.org/', u'SomePage'), 'http://example.org/SomePage'),
--- a/MoinMoin/action/AttachFile.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/action/AttachFile.py	Tue Aug 21 15:47:56 2007 +0200
@@ -330,9 +330,7 @@
 
             base, ext = os.path.splitext(file)
             get_url = getAttachUrl(pagename, file, request, escaped=1)
-            qfname = wikiutil.escape(file)
-            if ' ' in qfname:
-                qfname = wikiutil.quoteName(qfname)
+            escaped_fname = wikiutil.escape(file)
             parmdict = {'baseurl': baseurl, 'urlpagename': urlpagename, 'action': action,
                         'urlfile': urlfile, 'label_del': label_del,
                         'label_move': label_move,
@@ -341,7 +339,7 @@
                         'label_unzip': label_unzip,
                         'label_install': label_install,
                         'get_url': get_url, 'label_get': label_get,
-                        'file': qfname,
+                        'file': escaped_fname,
                         'fsize': fsize,
                         'fmtime': fmtime,
                         'pagename': pagename}
@@ -374,7 +372,7 @@
             parmdict['move_link'] = move_link
             html += ('<li>[%(del_link)s%(move_link)s'
                 '<a href="%(get_url)s">%(label_get)s</a>&nbsp;| %(viewlink)s]'
-                ' (%(fmtime)s, %(fsize)s KB) attachment:%(file)s</li>') % parmdict
+                ' (%(fmtime)s, %(fsize)s KB) [[attachment:%(file)s]]</li>') % parmdict
         html += "</ul>"
     else:
         if showheader:
@@ -993,10 +991,14 @@
         return
 
     request.write('<h2>' + _("Attachment '%(filename)s'") % {'filename': filename} + '</h2>')
+    # show a download link above the content
+    label = _('Download')
+    url = getAttachUrl(pagename, filename, request, escaped=1, do='get')
+    timestamp = htdocs_access(request) and "?%s" % time.time() or ''
+    request.write('<a href="%s%s">%s</a><br><br>' % (url, timestamp, label))
 
     mt = wikiutil.MimeType(filename=filename)
     if mt.major == 'image':
-        timestamp = htdocs_access(request) and "?%s" % time.time() or ''
         request.write('<img src="%s%s" alt="%s">' % (
             getAttachUrl(pagename, filename, request, escaped=1), timestamp, wikiutil.escape(filename, 1)))
         return
--- a/MoinMoin/action/MyPages.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/action/MyPages.py	Tue Aug 21 15:47:56 2007 +0200
@@ -24,7 +24,7 @@
     userhomewiki = request.cfg.user_homewiki
     if userhomewiki != 'Self' and userhomewiki != request.cfg.interwikiname:
         interwiki = wikiutil.getInterwikiHomePage(request, username=username)
-        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(request, '%s:"%s"' % interwiki)
+        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_interwiki(request, *interwiki)
         wikiurl = wikiutil.mapURL(request, wikiurl)
         homepageurl = wikiutil.join_wiki(wikiurl, wikitail)
         request.http_redirect('%s?action=MyPages' % homepageurl)
@@ -47,9 +47,9 @@
 the group pages.
 
 ||'''Add a new personal page:'''||'''Related access control list group:'''||
-||[[NewPage(HomepageReadWritePageTemplate,read-write page,%(username)s)]]||["%(username)s/ReadWriteGroup"]||
-||[[NewPage(HomepageReadPageTemplate,read-only page,%(username)s)]]||["%(username)s/ReadGroup"]||
-||[[NewPage(HomepagePrivatePageTemplate,private page,%(username)s)]]||%(username)s only||
+||<<NewPage(HomepageReadWritePageTemplate,read-write page,%(username)s)>>||["%(username)s/ReadWriteGroup"]||
+||<<NewPage(HomepageReadPageTemplate,read-only page,%(username)s)>>||["%(username)s/ReadGroup"]||
+||<<NewPage(HomepagePrivatePageTemplate,private page,%(username)s)>>||%(username)s only||
 
 """, formatted=False)
     pagecontent = pagecontent % locals()
--- a/MoinMoin/action/SyncPages.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/action/SyncPages.py	Tue Aug 21 15:47:56 2007 +0200
@@ -77,14 +77,14 @@
             if line[1]:
                 if line[2]:
                     macro_args = [line[1]] + list(line[2])
-                    message = u"[[GetText2(|%s)]]" % (packLine(macro_args), )
+                    message = u"<<GetText2(|%s)>>" % (packLine(macro_args), )
                 else:
-                    message = u"[[GetText(%s)]]" % (line[1], )
+                    message = u"<<GetText(%s)>>" % (line[1], )
             else:
                 message = u""
             table.append(table_line % {"smiley": line[0][1],
                                        "message": message,
-                                       "raw_suffix": line[3].replace("\n", "[[BR]]")})
+                                       "raw_suffix": line[3].replace("\n", "<<BR>>")})
 
         return "\n".join(table)
 
@@ -137,7 +137,7 @@
 
     def show_password_form(self):
         _ = self.request.getText
-        d = {"message": _(r"Please enter your password of your account at the remote wiki below. [[BR]] /!\ You should trust both wikis because the password could be read by the particular administrators."),
+        d = {"message": _(r"Please enter your password of your account at the remote wiki below. <<BR>> /!\ You should trust both wikis because the password could be read by the particular administrators."),
              "passwordlabel": _("Password"),
              "submit": _("Login"),
              "cancel": _("Cancel"),
@@ -256,7 +256,7 @@
         local_full_iwid = packLine([local.get_iwid(), local.get_interwiki_name()])
         remote_full_iwid = packLine([remote.get_iwid(), remote.get_interwiki_name()])
 
-        self.log_status(self.INFO, _("Synchronisation started -"), raw_suffix=" [[DateTime(%s)]]" % self.page._get_local_timestamp())
+        self.log_status(self.INFO, _("Synchronisation started -"), raw_suffix=" <<DateTime(%s)>>" % self.page._get_local_timestamp())
 
         l_pages = local.get_pages()
         r_pages = remote.get_pages(exclude_non_writable=direction != DOWN)
@@ -294,7 +294,7 @@
                 matching_tags = tags.fetch(iwid_full=remote.iwid_full, direction=match_direction)
                 matching_tags.sort()
                 if debug:
-                    self.log_status(ActionClass.INFO, raw_suffix="Tags: %r [[BR]] All: %r" % (matching_tags, tags.tags))
+                    self.log_status(ActionClass.INFO, raw_suffix="Tags: %r <<BR>> All: %r" % (matching_tags, tags.tags))
 
                 # some default values for non matching tags
                 normalised_name = None
--- a/MoinMoin/action/backup.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/action/backup.py	Tue Aug 21 15:47:56 2007 +0200
@@ -82,9 +82,9 @@
   * Restoring a backup will overwrite existing data, so be careful.
   * Rename it to <siteid>.tar.<compression> (remove the --date--time--UTC stuff).
   * Put the backup file into the backup_storage_dir (use scp, ftp, ...).
-  * Hit the [[GetText(Restore)]] button below.
+  * Hit the <<GetText(Restore)>> button below.
 
- * To make a backup, just hit the [[GetText(Backup)]] button and save the file
+ * To make a backup, just hit the <<GetText(Backup)>> button and save the file
    you get to a secure place.
 
 Please make sure your wiki configuration backup_* values are correct and complete.
--- a/MoinMoin/action/fckdialog.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/action/fckdialog.py	Tue Aug 21 15:47:56 2007 +0200
@@ -119,7 +119,7 @@
             helptext = ""
         helptexts.append(
             '''<div id="%s" style="DISPLAY: none">
-               <b>[[%s]]</b>
+               <b><<%s>></b>
                <br/>
                <textarea style="color:#000000" cols="37" rows="10" disabled="disabled">%s</textarea>
                </div>'''
--- a/MoinMoin/action/fullsearch.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/action/fullsearch.py	Tue Aug 21 15:47:56 2007 +0200
@@ -242,7 +242,7 @@
 
         hints.append(''.join([
             _("(!) You're performing a title search that might not include"
-                ' all related results of your search query in this wiki. [[BR]]'),
+                ' all related results of your search query in this wiki. <<BR>>'),
             ' ',
             f.url(1, href=request.page.url(request, querydict, escape=0,
                 relative=False)),
--- a/MoinMoin/action/recoverpass.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/action/recoverpass.py	Tue Aug 21 15:47:56 2007 +0200
@@ -81,9 +81,9 @@
 
             request.write(_("""
 == Recovering a lost password ==
-[[BR]]
+<<BR>>
 If you have forgotten your password, provide your email address and click on '''Mail me my account data'''.
-[[BR]]
+<<BR>>
 The email you get contains the encrypted password (so even if someone intercepts the mail, he won't know your REAL password). Just copy and paste it into the login mask into the password field and log in.
 After logging in you should change your password."""))
 
--- a/MoinMoin/auth/interwiki.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/auth/interwiki.py	Tue Aug 21 15:47:56 2007 +0200
@@ -30,8 +30,8 @@
             return ContinueLogin(user_obj)
 
         if verbose: request.log("interwiki auth: trying to auth %r" % username)
-        username = username.replace(' ', ':', 1) # XXX Hack because ':' is not allowed in name field
-        wikitag, wikiurl, name, err = wikiutil.resolve_wiki(request, username)
+        wikiname, username = username.split(' ', 1) # XXX Hack because ':' is not allowed in name field
+        wikitag, wikiurl, name, err = wikiutil.resolve_interwiki(request, wikiname, username)
 
         if verbose: request.log("interwiki auth: resolve wiki returned: %r %r %r %r" % (wikitag, wikiurl, name, err))
         if err or wikitag not in self.trusted_wikis:
--- a/MoinMoin/config/multiconfig.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/config/multiconfig.py	Tue Aug 21 15:47:56 2007 +0200
@@ -273,10 +273,10 @@
     editor_force = False
     editor_quickhelp = {# editor markup hints quickhelp
         'wiki': _("""\
- Emphasis:: [[Verbatim('')]]''italics''[[Verbatim('')]]; [[Verbatim(''')]]'''bold'''[[Verbatim(''')]]; [[Verbatim(''''')]]'''''bold italics'''''[[Verbatim(''''')]]; [[Verbatim('')]]''mixed ''[[Verbatim(''')]]'''''bold'''[[Verbatim(''')]] and italics''[[Verbatim('')]]; [[Verbatim(----)]] horizontal rule.
- Headings:: [[Verbatim(=)]] Title 1 [[Verbatim(=)]]; [[Verbatim(==)]] Title 2 [[Verbatim(==)]]; [[Verbatim(===)]] Title 3 [[Verbatim(===)]];   [[Verbatim(====)]] Title 4 [[Verbatim(====)]]; [[Verbatim(=====)]] Title 5 [[Verbatim(=====)]].
+ Emphasis:: <<Verbatim('')>>''italics''<<Verbatim('')>>; <<Verbatim(''')>>'''bold'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''bold italics'''''<<Verbatim(''''')>>; <<Verbatim('')>>''mixed ''<<Verbatim(''')>>'''''bold'''<<Verbatim(''')>> and italics''<<Verbatim('')>>; <<Verbatim(----)>> horizontal rule.
+ Headings:: <<Verbatim(=)>> Title 1 <<Verbatim(=)>>; <<Verbatim(==)>> Title 2 <<Verbatim(==)>>; <<Verbatim(===)>> Title 3 <<Verbatim(===)>>;   <<Verbatim(====)>> Title 4 <<Verbatim(====)>>; <<Verbatim(=====)>> Title 5 <<Verbatim(=====)>>.
  Lists:: space and one of: * bullets; 1., a., A., i., I. numbered items; 1.#n start numbering at n; space alone indents.
- Links:: [[Verbatim(JoinCapitalizedWords)]]; [[Verbatim(["brackets and double quotes"])]]; url; [url]; [url label].
+ Links:: <<Verbatim(JoinCapitalizedWords)>>; <<Verbatim([[target|linktext]])>>.
  Tables:: || cell text |||| cell text spanning 2 columns ||;    no trailing white space allowed after tables or titles.
 
 (!) For more help, see HelpOnEditing or SyntaxReference.
@@ -346,7 +346,7 @@
     mail_import_subpage_template = u"$from-$date-$subject" # used for mail import
     mail_import_pagename_search = ['subject', 'to', ] # where to look for target pagename (and in which order)
     mail_import_pagename_envelope = u"%s" # use u"+ %s/" to add "+ " and "/" automatically
-    mail_import_pagename_regex = r'\["([^"]*)"\]' # how to find/extract the pagename from the subject
+    mail_import_pagename_regex = r'\[\[([^\]]*)\]\]' # how to find/extract the pagename from the subject
     mail_import_wiki_addrs = [] # the e-mail addresses for e-mails that should go into the wiki
     mail_import_secret = ""
 
--- a/MoinMoin/converter/text_html_text_moin_wiki.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/converter/text_html_text_moin_wiki.py	Tue Aug 21 15:47:56 2007 +0200
@@ -1101,8 +1101,8 @@
 
             # interwiki link
             if class_ == "interwiki":
-                wikitag, wikiurl, wikitail, err = wikiutil.resolve_wiki(
-                    self.request, title + ":")
+                wikitag, wikiurl, wikitail, err = wikiutil.resolve_interwiki(
+                    self.request, title, "")
                 if not err and href.startswith(wikiurl):
                     pagename, qpagename = pagename_from_url(href[len(wikiurl):].lstrip('/'))
                     interwikiname = "%s:%s" % (wikitag, qpagename)
@@ -1217,7 +1217,7 @@
                     il_parms += ",height=%s" % height
                 if alt:
                     il_parms += ",alt=%s" % alt
-                self.text.extend([self.white_space, "[[ImageLink(%s)]]" % il_parms, self.white_space])
+                self.text.extend([self.white_space, "<<ImageLink(%s)>>" % il_parms, self.white_space])
 
         # Drawing image
         elif title and title.startswith("drawing:"):
--- a/MoinMoin/formatter/__init__.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/formatter/__init__.py	Tue Aug 21 15:47:56 2007 +0200
@@ -99,7 +99,7 @@
             IMPORTANT: on and off must be called with same parameters, see
                        also the text_html formatter.
         """
-        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, '%s:"%s"' % (interwiki, pagename))
+        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_interwiki(self.request, interwiki, pagename)
         if wikitag == 'Self' or wikitag == self.request.cfg.interwikiname:
             if '#' in wikitail:
                 wikitail, kw['anchor'] = wikitail.split('#', 1)
--- a/MoinMoin/formatter/text_docbook.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/formatter/text_docbook.py	Tue Aug 21 15:47:56 2007 +0200
@@ -367,7 +367,7 @@
         if not on:
             return self.url(on, kw)
 
-        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, '%s:"%s"' % (interwiki, pagename))
+        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_interwiki(self.request, interwiki, pagename)
         wikiurl = wikiutil.mapURL(self.request, wikiurl)
         href = wikiutil.join_wiki(wikiurl, wikitail)
 
--- a/MoinMoin/formatter/text_gedit.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/formatter/text_gedit.py	Tue Aug 21 15:47:56 2007 +0200
@@ -128,9 +128,9 @@
             return self.image(**kw)
 
         elif args is not None:
-            result = "[[%s(%s)]]" % (name, args)
+            result = "<<%s(%s)>>" % (name, args)
         else:
-            result = "[[%s]]" % name
+            result = "<<%s>>" % name
         return '<span style="background-color:#ffff11">%s</span>' % result
 
     def parser(self, parser_name, lines):
--- a/MoinMoin/formatter/text_html.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/formatter/text_html.py	Tue Aug 21 15:47:56 2007 +0200
@@ -481,8 +481,7 @@
         """
         @keyword title: override using the interwiki wikiname as title
         """
-        quoted = '%s:%s' % (interwiki, wikiutil.quoteName(pagename))
-        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, quoted)
+        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_interwiki(self.request, interwiki, pagename)
         wikiurl = wikiutil.mapURL(self.request, wikiurl)
         if wikitag == 'Self': # for own wiki, do simple links
             if '#' in wikitail:
@@ -615,7 +614,7 @@
             #self.request.log("attachment_link: url %s pagename %s filename %s" % (url, pagename, filename))
             fname = wikiutil.taintfilename(filename)
             if AttachFile.exists(self.request, pagename, fname):
-                target = AttachFile.getAttachUrl(pagename, fname, self.request)
+                target = AttachFile.getAttachUrl(pagename, fname, self.request, do='view')
                 title = "attachment:%s" % url
                 css = 'attachment'
             else:
@@ -638,10 +637,13 @@
                  (wikiutil.quoteWikinameURL(pagename),
                   wikiutil.url_quote_plus(fname))),
                 linktext % {'filename': self.text(fname)})
+        if not 'title' in kw:
+            kw['title'] = _('Inlined image: %(url)s') % {'url': self.text(url)}
+        # alt is required for images:
         if not 'alt' in kw:
-            kw['alt'] = _('Inlined image: %(url)s') % {'url': self.text(url)}
+            kw['alt'] = kw['title']
         return self.image(
-            title="attachment:%s" % url,
+            title=kw['title'],
             alt=kw['alt'],
             src=AttachFile.getAttachUrl(pagename, filename, self.request, addts=1),
             css="attachment")
--- a/MoinMoin/i18n/tools/check_i18n.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/i18n/tools/check_i18n.py	Tue Aug 21 15:47:56 2007 +0200
@@ -293,7 +293,7 @@
     print
     print '----'
     print
-    print '[[TableOfContents(2)]]'
+    print '<<TableOfContents(2)>>'
     print
     print
     print "= Translation Report ="
@@ -341,7 +341,7 @@
         print
         print "== %(name)s ==" % dict
         print
-        print "Maintainer: [[MailTo(%(maintainer)s)]]" % dict
+        print "Maintainer: <<MailTo(%(maintainer)s)>>" % dict
 
         # Print missing texts, if any
         if report[lang].missing():
--- a/MoinMoin/macro/AdvancedSearch.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/macro/AdvancedSearch.py	Tue Aug 21 15:47:56 2007 +0200
@@ -2,7 +2,7 @@
 """
     MoinMoin - AdvancedSearch Macro
 
-    [[AdvancedSearch]]
+    <<AdvancedSearch>>
         displays advanced search dialog.
 
     @license: GNU GPL, see COPYING for details.
--- a/MoinMoin/macro/AttachInfo.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/macro/AttachInfo.py	Tue Aug 21 15:47:56 2007 +0200
@@ -3,7 +3,7 @@
 
     A macro to produce information about attached pages
 
-    Usage: [[AttachInfo]]
+    Usage: <<AttachInfo>>
 
     @copyright: 2004 Jacob Cohen, Nigel Metheringham
     @license: GNU GPL, see COPYING for details
--- a/MoinMoin/macro/AttachList.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/macro/AttachList.py	Tue Aug 21 15:47:56 2007 +0200
@@ -3,7 +3,7 @@
 
     A macro to produce a list of attached files
 
-    Usage: [[AttachList([pagename,mime_type])]]
+    Usage: <<AttachList([pagename,mime_type])>>
 
     If pagename isn't set, the current pagename is used.
     If mime_type isn't given, all files are listed.
--- a/MoinMoin/macro/EmbedObject.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/macro/EmbedObject.py	Tue Aug 21 15:47:56 2007 +0200
@@ -8,7 +8,7 @@
         the kind of application.
 
     CALLING SEQUENCE:
-        [[EmbedObject(attachment[,width=width][,height=height][,alt=Embedded mimetpye/xy])]]
+        <<EmbedObject(attachment[,width=width][,height=height][,alt=Embedded mimetpye/xy])>>
 
     SUPPORTED MIMETYPES:
          application/x-shockwave-flash
@@ -74,19 +74,19 @@
         as PDF file"
 
     EXAMPLE:
-        [[EmbedObject]]
-        [[EmbedObject(example.swf,alt=A flash movie showing the rotating moin logo)]]
-        [[EmbedObject(example.mid,alt=Background sound of wikipage: oceanwaves)]]
-        [[EmbedObject(example.pdf)]]
-        [[EmbedObject(example.svg)]]
-        [[EmbedObject(example.mp3)]]
-        [[EmbedObject(example.vss)]]
+        <<EmbedObject>>
+        <<EmbedObject(example.swf,alt=A flash movie showing the rotating moin logo)>>
+        <<EmbedObject(example.mid,alt=Background sound of wikipage: oceanwaves)>>
+        <<EmbedObject(example.pdf)>>
+        <<EmbedObject(example.svg)>>
+        <<EmbedObject(example.mp3)>>
+        <<EmbedObject(example.vss)>>
 
-        [[EmbedObject(example.swf,width=637,height=392)]]
-        [[EmbedObject(SlideShow/example.swf,width=637,height=392)]]
-        [[EmbedObject(SlideShow/example.swf,width=637,height=392)]]
-        [[EmbedObject(SlideShow/example.swf,width=637,height=392,play=true,loop=false)]]
-        [[EmbedObject(SlideShow/example.swf,width=637,height=392,quality=low)]]
+        <<EmbedObject(example.swf,width=637,height=392)>>
+        <<EmbedObject(SlideShow/example.swf,width=637,height=392)>>
+        <<EmbedObject(SlideShow/example.swf,width=637,height=392)>>
+        <<EmbedObject(SlideShow/example.swf,width=637,height=392,play=true,loop=false)>>
+        <<EmbedObject(SlideShow/example.swf,width=637,height=392,quality=low)>>
 
 
     PROCEDURE:
@@ -266,7 +266,7 @@
         _ = self._
 
         if not self.target:
-            msg = _('Not enough arguments to EmbedObject macro! Try [[EmbedObject(attachment [,width=width] [,height=height] [,alt=Embedded mimetpye/xy])]]', formatted=False)
+            msg = _('Not enough arguments to EmbedObject macro! Try <<EmbedObject(attachment [,width=width] [,height=height] [,alt=Embedded mimetpye/xy])>>', formatted=False)
             return "%s%s%s" % (self.formatter.sysmsg(1), self.formatter.text(msg), self.formatter.sysmsg(0))
 
         pagename, fname = AttachFile.absoluteName(self.target, self.formatter.page.page_name)
--- a/MoinMoin/macro/FullSearch.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/macro/FullSearch.py	Tue Aug 21 15:47:56 2007 +0200
@@ -2,15 +2,15 @@
 """
     MoinMoin - FullSearch Macro
 
-    [[FullSearch]]
+    <<FullSearch>>
         displays a search dialog, as it always did.
 
-    [[FullSearch()]]
+    <<FullSearch()>>
         does the same as clicking on the page title, only that
         the result is embedded into the page. note the '()' after
         the macro name, which is an empty argument list.
 
-    [[FullSearch(Help)]]
+    <<FullSearch(Help)>>
         embeds a search result into a page, as if you entered
         'Help' into the search box.
 
--- a/MoinMoin/macro/Hits.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/macro/Hits.py	Tue Aug 21 15:47:56 2007 +0200
@@ -5,7 +5,7 @@
     This macro is used to show the cumulative hits of the wikipage where the Macro is called from.
     Optionally you could count how much this page or all pages were changed or viewed.
 
-    [[Hits([all=(0,1)],[filter=(VIEWPAGE,SAVEPAGE)]]
+    <<Hits([all=(0,1)],[filter=(VIEWPAGE,SAVEPAGE)>>
 
         all: if set to 1/True/yes then cumulative hits over all wiki pages is returned.
              Default is 0/False/no.
--- a/MoinMoin/macro/ImageLink.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/macro/ImageLink.py	Tue Aug 21 15:47:56 2007 +0200
@@ -8,7 +8,7 @@
     If no target is given the link will point to the image itself.
 
     Syntax:
-        [[ImageLink(image, [target,] [width=width, [height=height]])]]
+        <<ImageLink(image, [target,] [width=width, [height=height>>)>>
 
     Parameters:
         image: image attachment file name or the URL of an image
@@ -20,17 +20,17 @@
         alt: text for img tag "alt" attribute
 
     Examples:
-        [[ImageLink(München.png,München,height=100)]]
-        [[ImageLink(Images/München.png,München,height=100)]]
-        [[ImageLink(http://webcam.portalmuc.de/images/webcam/webcam_marienplatz.jpg,München Marienplatz)]]
-        [[ImageLink(plot.png,width=200)]]
-        [[ImageLink(plot.png,height=200)]]
-        [[ImageLink(plot.png)]]
-        [[ImageLink(http://webcam.portalmuc.de/images/webcam/webcam_marienplatz.jpg,http://www.muenchen.de,width=150)]]
-        [[ImageLink(münchen.png,http://www.muenchen.de,width=50)]]
-        [[ImageLink(http://webcam.portalmuc.de/images/webcam/webcam_marienplatz.jpg)]]
-        [[ImageLink(example.png,alt=whateveryouwant(üöä))]]
-        [[ImageLink(http://moinmoin.wikiwikiweb.de/OliverSiemoneit?action=AttachFile&do=get&target=screenshot.png,width=647,height=517,alt=OliverSiemoneit?action=AttachFile&do=get&target=screenshot,FrontPage)]]
+        <<ImageLink(München.png,München,height=100)>>
+        <<ImageLink(Images/München.png,München,height=100)>>
+        <<ImageLink(http://webcam.portalmuc.de/images/webcam/webcam_marienplatz.jpg,München Marienplatz)>>
+        <<ImageLink(plot.png,width=200)>>
+        <<ImageLink(plot.png,height=200)>>
+        <<ImageLink(plot.png)>>
+        <<ImageLink(http://webcam.portalmuc.de/images/webcam/webcam_marienplatz.jpg,http://www.muenchen.de,width=150)>>
+        <<ImageLink(münchen.png,http://www.muenchen.de,width=50)>>
+        <<ImageLink(http://webcam.portalmuc.de/images/webcam/webcam_marienplatz.jpg)>>
+        <<ImageLink(example.png,alt=whateveryouwant(üöä))>>
+        <<ImageLink(http://moinmoin.wikiwikiweb.de/OliverSiemoneit?action=AttachFile&do=get&target=screenshot.png,width=647,height=517,alt=OliverSiemoneit?action=AttachFile&do=get&target=screenshot,FrontPage)>>
 
     History:
         Jeff Kunce:
@@ -57,7 +57,7 @@
                    width and height and probably other keywords must be given as keywords (e.g. height=20)
             2004-12-31 Version 1.3.1-3 code clean up
             2005-01-16 Bug fixed in the errorhandler - found and patched by Malte Helmert
-            2005-03-05 Version 1.3.3-5 Bug fixed found by cypress ("If I put [[ImageLink(moinmoin.png)]] it bombs")
+            2005-03-05 Version 1.3.3-5 Bug fixed found by cypress ("If I put <<ImageLink(moinmoin.png)>> it bombs")
             2005-03-28 Version 1.3.3-6 feature request added by CDPark:
                        "Can we use an external image? And an external target?"
             2005-04-16 Version 1.3.3-7 no default alt tag definition as requested by CDPark and AlexanderSchremmer
@@ -145,7 +145,7 @@
     pp, pp_count, kw, kw_count = explore_args(args, kwAllowed)
 
     if not pp_count or pp_count and not pp[0]:
-        msg = 'Not enough arguments to ImageLink macro! e.g. [[ImageLink(example.png, WikiName, width=200)]].'
+        msg = 'Not enough arguments to ImageLink macro! e.g. <<ImageLink(example.png, WikiName, width=200)>>.'
         return "%s%s%s" % (formatter.sysmsg(1), formatter.text(msg), formatter.sysmsg(0))
 
     image = pp[0]
@@ -216,7 +216,8 @@
         if ":" in target:
             if target.startswith('wiki:'):
                 target = target[5:]
-            wikitag, wikiurl, wikitail, error = wikiutil.resolve_wiki(request, target)
+            wikiname, pagename = wikiutil.split_interwiki(target)
+            wikitag, wikiurl, wikitail, error = wikiutil.resolve_interwiki(request, wikiname, pagename)
             url = wikiurl + wikiutil.quoteWikinameURL(wikitail)
             return "%s%s%s" % (formatter.url(1, url),
                                formatter.image(**kw),
--- a/MoinMoin/macro/MonthCalendar.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/macro/MonthCalendar.py	Tue Aug 21 15:47:56 2007 +0200
@@ -91,52 +91,52 @@
         * adapted to moin 1.7 new macro parameter parsing
 
     Usage:
-        [[MonthCalendar(BasePage,year,month,monthoffset,monthoffset2,height6)]]
+        <<MonthCalendar(BasePage,year,month,monthoffset,monthoffset2,height6)>>
 
         each parameter can be empty and then defaults to currentpage or currentdate or monthoffset=0
 
     Samples (paste that to one of your pages for a first try):
 
 Calendar of current month for current page:
-[[MonthCalendar]]
+<<MonthCalendar>>
 
 Calendar of last month:
-[[MonthCalendar(,,,-1)]]
+<<MonthCalendar(,,,-1)>>
 
 Calendar of next month:
-[[MonthCalendar(,,,+1)]]
+<<MonthCalendar(,,,+1)>>
 
 Calendar of Page SampleUser, this years december:
-[[MonthCalendar(SampleUser,,12)]]
+<<MonthCalendar(SampleUser,,12)>>
 
 Calendar of current Page, this years december:
-[[MonthCalendar(,,12)]]
+<<MonthCalendar(,,12)>>
 
 Calendar of December, 2001:
-[[MonthCalendar(,2001,12)]]
+<<MonthCalendar(,2001,12)>>
 
 Calendar of the month two months after December, 2001
 (maybe doesn't make much sense, but is possible)
-[[MonthCalendar(,2001,12,+2)]]
+<<MonthCalendar(,2001,12,+2)>>
 
 Calendar of year 2002 (every month padded to height of 6):
 ||||||Year 2002||
-||[[MonthCalendar(,2002,1,,,1)]]||[[MonthCalendar(,2002,2,,,1)]]||[[MonthCalendar(,2002,3,,,1)]]||
-||[[MonthCalendar(,2002,4,,,1)]]||[[MonthCalendar(,2002,5,,,1)]]||[[MonthCalendar(,2002,6,,,1)]]||
-||[[MonthCalendar(,2002,7,,,1)]]||[[MonthCalendar(,2002,8,,,1)]]||[[MonthCalendar(,2002,9,,,1)]]||
-||[[MonthCalendar(,2002,10,,,1)]]||[[MonthCalendar(,2002,11,,,1)]]||[[MonthCalendar(,2002,12,,,1)]]||
+||<<MonthCalendar(,2002,1,,,1)>>||<<MonthCalendar(,2002,2,,,1)>>||<<MonthCalendar(,2002,3,,,1)>>||
+||<<MonthCalendar(,2002,4,,,1)>>||<<MonthCalendar(,2002,5,,,1)>>||<<MonthCalendar(,2002,6,,,1)>>||
+||<<MonthCalendar(,2002,7,,,1)>>||<<MonthCalendar(,2002,8,,,1)>>||<<MonthCalendar(,2002,9,,,1)>>||
+||<<MonthCalendar(,2002,10,,,1)>>||<<MonthCalendar(,2002,11,,,1)>>||<<MonthCalendar(,2002,12,,,1)>>||
 
 Current calendar of me, also showing entries of A and B:
-[[MonthCalendar(MyPage*TestUserA*TestUserB)]]
+<<MonthCalendar(MyPage*TestUserA*TestUserB)>>
 
 SubPage calendars:
-[[MonthCalendar(MyName/CalPrivate)]]
-[[MonthCalendar(MyName/CalBusiness)]]
-[[MonthCalendar(MyName/CalBusiness*MyName/CalPrivate)]]
+<<MonthCalendar(MyName/CalPrivate)>>
+<<MonthCalendar(MyName/CalBusiness)>>
+<<MonthCalendar(MyName/CalBusiness*MyName/CalPrivate)>>
 
 
 Anniversary Calendars: (no year data)
-[[MonthCalendar(Yearly,,,+1,,6,1)]]
+<<MonthCalendar(Yearly,,,+1,,6,1)>>
 
 This creates calendars of the format Yearly/MM-DD
 By leaving out the year, you can set birthdays, and anniversaries in this
@@ -144,7 +144,7 @@
 
 This creates a calendar which uses MonthCalendarTemplate for directly editing
 nonexisting day pages:
-[[MonthCalendar(,,,,,,MonthCalendarTemplate)]]
+<<MonthCalendar(,,,,,,MonthCalendarTemplate)>>
 """
 
 Dependencies = ['namespace', 'time', ]
--- a/MoinMoin/macro/NewPage.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/macro/NewPage.py	Tue Aug 21 15:47:56 2007 +0200
@@ -25,16 +25,16 @@
 
     Usage:
 
-        [[NewPage(template, buttonLabel, parentPage)]]
+        <<NewPage(template, buttonLabel, parentPage)>>
 
     Examples:
 
-        [[NewPage]]
+        <<NewPage>>
 
             Create an input field with 'Create New Page' button. The new
             page will not use a template.
 
-        [[NewPage(BugTemplate, Create New Bug, MoinMoinBugs)]]
+        <<NewPage(BugTemplate, Create New Bug, MoinMoinBugs)>>
 
             Create an input field with button labeled 'Create New
             Bug'.  The new page will use the BugTemplate template,
@@ -52,7 +52,7 @@
     def getArgs(self, argstr):
         """ Temporary function until Oliver Graf args parser is finished
 
-        @param argstr: string from the wiki markup [[NewPage(string)]]
+        @param argstr: string from the wiki markup <<NewPage(string)>>
         @rtype: dict
         @return: dictionary with macro options
         """
--- a/MoinMoin/macro/RandomQuote.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/macro/RandomQuote.py	Tue Aug 21 15:47:56 2007 +0200
@@ -5,8 +5,8 @@
     Selects a random quote from FortuneCookies or a given page.
 
     Usage:
-        [[RandomQuote()]]
-        [[RandomQuote(WikiTips)]]
+        <<RandomQuote()>>
+        <<RandomQuote(WikiTips)>>
 
     Comments:
         It will look for list delimiters on the page in question.
--- a/MoinMoin/macro/ShowSmileys.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/macro/ShowSmileys.py	Tue Aug 21 15:47:56 2007 +0200
@@ -2,7 +2,7 @@
 """
     MoinMoin - List all defined smileys
 
-    [[ShowSmileys]] will display a table of all the available smileys.
+    <<ShowSmileys>> will display a table of all the available smileys.
 
     Based on code by Nick Trout <trout@users.sf.net>
 
--- a/MoinMoin/macro/__init__.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/macro/__init__.py	Tue Aug 21 15:47:56 2007 +0200
@@ -45,7 +45,7 @@
 
 
 #############################################################################
-### Macros - Handlers for [[macroname]] markup
+### Macros - Handlers for <<macroname>> markup
 #############################################################################
 
 class Macro:
@@ -101,7 +101,7 @@
 
     def format_error(self, err):
         """ format an error object for output instead of normal macro output """
-        return self.formatter.text(u'[[%s: %s]]' % (self.name, err.args[0]))
+        return self.formatter.text(u'<<%s: %s>>' % (self.name, err.args[0]))
 
     def execute(self, macro_name, args):
         """ Get and execute a macro
--- a/MoinMoin/macro/_tests/test_ImageLink.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/macro/_tests/test_ImageLink.py	Tue Aug 21 15:47:56 2007 +0200
@@ -7,7 +7,7 @@
     @license: GNU GPL, see COPYING for details.
 """
 import os
-from MoinMoin import macro
+from MoinMoin import macro, wikiutil
 from MoinMoin.logfile import eventlog
 from MoinMoin.Page import Page
 from MoinMoin.PageEditor import PageEditor
@@ -58,11 +58,12 @@
         """ macro ImageLink test: 'no args for ImageLink (ImageLink is executed on FrontPage) """
         #self._createTestPage('This is an example to test a macro')
         result = self._test_macro('ImageLink', '')
-        expected = '<div class="message">Not enough arguments to ImageLink macro! e.g. [[ImageLink(example.png, WikiName, width=200)]].</div>'
+        expected = '<div class="message">%s</div>' % wikiutil.escape(
+                'Not enough arguments to ImageLink macro! e.g. <<ImageLink(example.png, WikiName, width=200)>>.')
         assert result == expected
 
     def testImageLinkTwoParamsNoKeyword(self):
-        """ macro ImageLink test: [[ImageLink(http://static.wikiwikiweb.de/logos/moindude.png, FrontPage)]] """
+        """ macro ImageLink test: <<ImageLink(http://static.wikiwikiweb.de/logos/moindude.png, FrontPage)>> """
         self.shouldDeleteTestPage = False
 
         result = self._test_macro('ImageLink', 'http://static.wikiwikiweb.de/logos/moindude.png, FrontPage')
@@ -70,7 +71,7 @@
         assert result == expected
 
     def testImageLinkTwoParamsOneKeyword(self):
-        """ macro ImageLink test: [[ImageLink(http://static.wikiwikiweb.de/logos/moindude.png, alt=The old dude, FrontPage)]]
+        """ macro ImageLink test: <<ImageLink(http://static.wikiwikiweb.de/logos/moindude.png, alt=The old dude, FrontPage)>>
         order of keywords to parameter list is independent
         """
         self.shouldDeleteTestPage = True
--- a/MoinMoin/mail/mailimport.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/mail/mailimport.py	Tue Aug 21 15:47:56 2007 +0200
@@ -253,7 +253,7 @@
                 break
 
     # build an attachment link table for the page with the e-mail
-    attachment_links = [""] + [u'''[attachment:%s %s]''' % (wikiutil.quoteName("%s/%s" % (pagename, att)), att) for att in attachments]
+    attachment_links = [""] + [u'''[[attachment:%s|%s]]''' % ("%s/%s" % (pagename, att), att) for att in attachments]
 
     # assemble old page content and new mail body together
     old_content = Page(request, pagename).get_raw_body()
@@ -264,7 +264,7 @@
 
     #if not (generate_summary and "/" in pagename):
     #generate header in any case:
-    new_content += u"'''Mail: %s (%s, [[DateTime(%s)]])'''\n\n" % (msg['subject'], email_to_markup(request, msg['from_addr']), msg['date'])
+    new_content += u"'''Mail: %s (%s, <<DateTime(%s)>>)'''\n\n" % (msg['subject'], email_to_markup(request, msg['from_addr']), msg['date'])
 
     new_content += d['content']
     new_content += "\n" + u"\n * ".join(attachment_links)
@@ -288,21 +288,21 @@
             elif table_ends is not None and not line.startswith("||"):
                 break
 
-        # in order to let the gettext system recognise the [[GetText]] calls used below,
+        # in order to let the gettext system recognise the <<GetText>> calls used below,
         # we must repeat them here:
         [_("Date"), _("From"), _("To"), _("Content"), _("Attachments")]
 
         table_header = (u"\n\n## mail_overview (don't delete this line)\n" +
-                        u"|| '''[[GetText(Date)]] ''' || '''[[GetText(From)]] ''' || '''[[GetText(To)]] ''' || '''[[GetText(Content)]] ''' || '''[[GetText(Attachments)]] ''' ||\n"
+                        u"|| '''<<GetText(Date)>> ''' || '''<<GetText(From)>> ''' || '''<<GetText(To)>> ''' || '''<<GetText(Content)>> ''' || '''<<GetText(Attachments)>> ''' ||\n"
                        )
 
         from_col = email_to_markup(request, msg['from_addr'])
         to_col = ' '.join([email_to_markup(request, (realname, mailaddr))
                            for realname, mailaddr in msg['target_addrs'] if not mailaddr in wiki_addrs])
-        subj_col = '[%s %s]' % (wikiutil.quoteName(pagename), msg['subject'])
+        subj_col = '[[%s|%s]]' % (pagename, msg['subject'])
         date_col = msg['date']
         attach_col = " ".join(attachment_links)
-        new_line = u'|| [[DateTime(%s)]] || %s || %s || %s || %s ||' % (date_col, from_col, to_col, subj_col, attach_col)
+        new_line = u'|| <<DateTime(%s)>> || %s || %s || %s || %s ||' % (date_col, from_col, to_col, subj_col, attach_col)
         if found_table is not None:
             content = "\n".join(old_content[:table_ends] + [new_line] + old_content[table_ends:])
         else:
--- a/MoinMoin/parser/_tests/test_text_moin_wiki.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/parser/_tests/test_text_moin_wiki.py	Tue Aug 21 15:47:56 2007 +0200
@@ -72,7 +72,7 @@
             '=== heading 3 ===\n',
             '==== heading 4 ====\n',
             '===== heading 5 =====\n',
-            # '[[en]]\n', XXX crashes
+            # '<<en>>\n', XXX crashes
             )
         for item in markup:
             text = item + 'Paragraph'
@@ -130,12 +130,12 @@
         around heading text does not matter.
         """
         standard = """
-[[TableOfContents]]
+<<TableOfContents>>
 = heading =
 Text
 """
         withWhitespace = """
-[[TableOfContents]]
+<<TableOfContents>>
 =   heading   =
 Text
 """
@@ -166,11 +166,11 @@
     needle = re.compile(text % r'(.+)')
     _tests = (
         # test                                   expected
-        (u'[[DateTime(259200)]]',                '1970-01-04 00:00:00'),
-        (u'[[DateTime(2003-03-03T03:03:03)]]',   '2003-03-03 03:03:03'),
-        (u'[[DateTime(2000-01-01T00:00:00Z)]]',  '2000-01-01 00:00:00'), # works for Europe/Vilnius
-        (u'[[Date(2002-02-02T01:02:03Z)]]',      '2002-02-02'),
-        (u'[[DateTime(1970-01-06T00:00:00)]]',   '1970-01-06 00:00:00'), # fails e.g. for Europe/Vilnius
+        (u'<<DateTime(259200)>>',                '1970-01-04 00:00:00'),
+        (u'<<DateTime(2003-03-03T03:03:03)>>',   '2003-03-03 03:03:03'),
+        (u'<<DateTime(2000-01-01T00:00:00Z)>>',  '2000-01-01 00:00:00'), # works for Europe/Vilnius
+        (u'<<Date(2002-02-02T01:02:03Z)>>',      '2002-02-02'),
+        (u'<<DateTime(1970-01-06T00:00:00)>>',   '1970-01-06 00:00:00'), # fails e.g. for Europe/Vilnius
         )
 
     def class_setup(self):
@@ -292,7 +292,7 @@
 
     def testEscapeInGetTextMacro(self):
         """ parser.wiki: escape html markup in GetText macro """
-        test = "text [[GetText(<escape-me>)]] text"
+        test = "text <<GetText(<escape-me>)>> text"
         self._test(test)
 
     def testEscapeInGetTextFormatted(self):
@@ -302,7 +302,7 @@
 
     def testEscapeInGetTextFormatedLink(self):
         """ parser.wiki: escape html markup in getText formatted call with link """
-        test = self.request.getText('["<escape-me>"]', formatted=1)
+        test = self.request.getText('[[<escape-me>]]', formatted=1)
         self._test(test)
 
     def testEscapeInGetTextUnFormatted(self):
@@ -532,15 +532,14 @@
     text = 'AAA %s AAA'
     needle = re.compile(text % r'(.+)')
     _tests = (
-        # test,                       expected
-        ('["something"]',             '<a class="nonexistent" href="./something">something</a>'),
-        ("['something']",             "['something']"),
-        ('MoinMoin:"something"',      '<a class="interwiki" href="http://moinmoin.wikiwikiweb.de/something" title="MoinMoin">something</a>'),
-        ('MoinMoin:"with space"',     '<a class="interwiki" href="http://moinmoin.wikiwikiweb.de/with%20space" title="MoinMoin">with space</a>'),
-        ('RFC:"1 2 3"',               '<a class="interwiki" href="http://www.ietf.org/rfc/rfc1%202%203" title="RFC">1 2 3</a>'),
-        ("RFC:'something else'",      "RFC:'something else'"),
-        ('["with "" quote"]',         '<a class="nonexistent" href="./with%20%22%20quote">with " quote</a>'),
-        ('MoinMoin:"with "" quote"',  '<a class="interwiki" href="http://moinmoin.wikiwikiweb.de/with%20%22%20quote" title="MoinMoin">with " quote</a>'),
+        # test,           expected
+        ('[[something]]', '<a class="nonexistent" href="./something">something</a>'),
+        ('[[something|some text]]', '<a class="nonexistent" href="./something">some text</a>'),
+        ('MoinMoin:something', '<a class="interwiki" href="http://moinmoin.wikiwikiweb.de/something" title="MoinMoin">something</a>'),
+        ('[[MoinMoin:something|some text]]', '<a class="interwiki" href="http://moinmoin.wikiwikiweb.de/something" title="MoinMoin">some text</a>'),
+        ('[[MoinMoin:with space]]', '<a class="interwiki" href="http://moinmoin.wikiwikiweb.de/with%20space" title="MoinMoin">with space</a>'),
+        ('[[MoinMoin:with space|some text]]', '<a class="interwiki" href="http://moinmoin.wikiwikiweb.de/with%20space" title="MoinMoin">some text</a>'),
+        ('[[http://google.com/|google]]', '<a class="http" href="http://google.com/">google</a>'),
         )
 
     def testTextFormating(self):
@@ -554,15 +553,6 @@
             together_test.append(test)
             together_expected.append(expected)
 
-        # now test all together to make sure one quoting doesn't
-        # "leak" into the next
-        for joint in ('', 'lala " lala ', 'lala "" lala '):
-            test = joint.join(together_test)
-            expected = joint.join(together_expected)
-            html = self.parse(self.text % test)
-            result = self.needle.search(html).group(1)
-            assert result == expected
-
 
 coverage_modules = ['MoinMoin.parser.text_moin_wiki']
 
--- a/MoinMoin/parser/text_creole.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/parser/text_creole.py	Tue Aug 21 15:47:56 2007 +0200
@@ -614,9 +614,9 @@
         ])
 
     def interwiki_link_emit(self, node):
-        word = node.content
+        wiki, page = wikiutil.split_interwiki(node.content)
         wikitag, wikiurl, wikitail, wikitag_bad = \
-            wikiutil.resolve_wiki(self.request, word)
+            wikiutil.resolve_interwiki(self.request, wiki, page)
         href = wikiutil.join_wiki(wikiurl, wikitail)
         return ''.join([
             self.formatter.interwikilink(1, wikitag, wikitail),
--- a/MoinMoin/parser/text_moin_wiki.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/parser/text_moin_wiki.py	Tue Aug 21 15:47:56 2007 +0200
@@ -8,6 +8,22 @@
     @license: GNU GPL, see COPYING for details.
 """
 
+ur'''
+
+    def anchor_link_emit(self, node):
+        return ''.join([
+            self.formatter.url(1, node.content, css='anchor'),
+            self.emit_children(node),
+            self.formatter.url(0),
+        ])
+
+TODO: use this for links to anchors
+    res.append(self.formatter.anchorlink(1, words[0][1:]))
+    res.append(self.formatter.text(words[1]))
+    res.append(self.formatter.anchorlink(0))
+
+'''
+
 import re
 from MoinMoin import config, wikiutil, macro
 
@@ -30,85 +46,262 @@
     Dependencies = Dependencies
 
     # some common strings
+    CHILD_PREFIX = wikiutil.CHILD_PREFIX
+    CHILD_PREFIX_LEN = wikiutil.CHILD_PREFIX_LEN
     PARENT_PREFIX = wikiutil.PARENT_PREFIX
-    # quoted strings (we require that there is at least one char (that is not the quoting char)
-    # inside to not confuse stuff like '''Contact:''' (just a bold Contact:) with interwiki markup
-    # OtherWiki:'Page with blanks'
-    dq_string = ur'("([^"]|"")+?"(?!"))' # double quoted string
-    attachment_schemas = ["attachment", "inline", "drawing"]
+    PARENT_PREFIX_LEN = wikiutil.PARENT_PREFIX_LEN
+
     punct_pattern = re.escape(u'''"\'}]|:,.)?!''')
-    punct_no_quote_pattern = re.escape(u'''}]|:,.)?!''')
-    url_pattern = (u'http|https|ftp|nntp|news|mailto|telnet|wiki|file|irc|' +
-            u'|'.join(attachment_schemas) +
-            (config.url_schemas and u'|' + u'|'.join(config.url_schemas) or ''))
+    url_scheme = (u'http|https|ftp|nntp|news|mailto|telnet|wiki|file|irc' +
+                 (config.url_schemas and (u'|' + u'|'.join(config.url_schemas)) or ''))
 
     # some common rules
-    word_rule = ur'(?:(?<![%(u)s%(l)s])|^)%(parent)s(?:%(subpages)s(?:[%(u)s][%(l)s]+){2,})+(?![%(u)s%(l)s]+)' % {
+    url_rule = ur'''
+        (^|(?<!\w))  # require either beginning of line or some whitespace to the left
+        (?P<url_target>  # capture whole url there
+         (?P<url_scheme>%(url_scheme)s)  # some scheme
+         \:
+         \S+?  # anything non-whitespace
+        )
+        ($|(?=\s|[%(punct)s](\s|$)))  # require either end of line or some whitespace or some punctuation+blank/eol afterwards
+    ''' % {
+        'url_scheme': url_scheme,
+        'punct': punct_pattern,
+    }
+
+    word_rule = ur'''
+        (?:
+         (?<![%(u)s%(l)s])  # require anything not upper/lower before
+         |
+         ^  # ... or beginning of line
+        )
+        (?P<word_bang>\!)?  # configurable: avoid getting CamelCase rendered as link
+        (?P<word_parent_prefix>%(parent)s)?  # there might be ../ parent prefix    XXX TODO: there might be even multiple!!
+        (?P<word_name>
+         (
+          (%(child)s)?  # there might be / child prefix
+          (?:[%(u)s][%(l)s]+){2,}  # at least 2 upper>lower transitions make CamelCase
+         )+  # we can have MainPage/SubPage/SubSubPage ...
+        )
+        (?![%(u)s%(l)s]+)  # require anything NOT upper/lower following
+    ''' % {
         'u': config.chars_upper,
         'l': config.chars_lower,
-        'subpages': wikiutil.CHILD_PREFIX + '?',
-        'parent': ur'(?:%s)?' % re.escape(PARENT_PREFIX),
-    }
-    url_rule = ur'%(url_guard)s(%(url)s)\:(([^\s\<%(punct)s]|([%(punctnq)s][^\s\<%(punct)s]))+|%(dq_string)s)' % {
-        'url_guard': ur'(^|(?<!\w))',
-        'url': url_pattern,
-        'punct': punct_pattern,
-        'punctnq': punct_no_quote_pattern,
-        'dq_string': dq_string,
+        'child': re.escape(CHILD_PREFIX),
+        'parent': re.escape(PARENT_PREFIX),
     }
 
-    ol_rule = ur"^\s+(?:[0-9]+|[aAiI])\.(?:#\d+)?\s"
-    dl_rule = ur"^\s+.*?::\s"
+    # link targets:
+    extern_rule = r'(?P<extern_addr>(?P<extern_scheme>%s)\:.*)' % url_scheme
+    attach_rule = r'(?P<attach_scheme>attachment|drawing)\:(?P<attach_addr>.*)'
+    inter_rule = r'(?P<inter_wiki>[A-Z][a-zA-Z]+):(?P<inter_page>.*)'
+    page_rule = r'(?P<page_name>.*)'
+
+    link_target_rules = r'|'.join([
+        extern_rule,
+        attach_rule,
+        inter_rule,
+        page_rule,
+    ])
+    link_target_re = re.compile(link_target_rules, re.VERBOSE|re.UNICODE)
+
+    transclude_rule = r"""
+        (?P<transclude>
+            \{\{
+            (?P<transclude_target>.+?)\s*  # usually image target (eat trailing space)
+            (\|\s*(?P<transclude_args>.+?)\s*)?  # usually image alt text (optional, strip space)
+            \}\}
+        )
+    """
+    text_rule = r"""
+        (?P<simple_text>
+            .+  # some text (not empty)
+        )
+    """
+    # link descriptions:
+    link_desc_rules = r'|'.join([
+            transclude_rule,
+            text_rule,
+            # _get_rule('break', inline_tab),
+            # _get_rule('char', inline_tab),
+    ])
+    link_desc_re = re.compile(link_desc_rules, re.VERBOSE|re.UNICODE)
+
+    # transclude descriptions:
+    transclude_desc_rules = r'|'.join([
+            text_rule,
+            # _get_rule('break', inline_tab),
+            # _get_rule('char', inline_tab),
+    ])
+    transclude_desc_re = re.compile(transclude_desc_rules, re.VERBOSE|re.UNICODE)
+
+    # lists:
+    ol_rule = ur"""
+        ^\s+  # indentation
+        (?:[0-9]+|[aAiI])\. # arabic, alpha, roman counting
+        (?:\#\d+)?  # optional start number
+        \s  # require one blank afterwards
+    """
+    ol_re = re.compile(ol_rule, re.VERBOSE|re.UNICODE)
+
+    dl_rule = ur"""
+        ^\s+  # indentation
+        .*?::  # definition term::
+        \s  # require on blank afterwards
+    """
+    dl_re = re.compile(dl_rule, re.VERBOSE|re.UNICODE)
 
     # this is used inside <pre> / parser sections (we just want to know when it's over):
-    pre_formatting_rules = ur"""(?P<pre>(\}\}\}))"""
+    pre_scan_rule = ur"""
+(?P<pre>
+    \}\}\}  # in pre, we only look for the end of the pre
+)
+"""
+    pre_scan_re = re.compile(pre_scan_rule, re.VERBOSE|re.UNICODE)
 
-    # the big, fat, ugly one ;)
-    formatting_rules = ur"""(?P<ent_numeric>&#(\d{1,5}|x[0-9a-fA-F]+);)
-(?P<emph_ibb>'''''(?=[^']+'''))
-(?P<emph_ibi>'''''(?=[^']+''))
-(?P<emph_ib_or_bi>'{5}(?=[^']))
-(?P<emph>'{2,3})
-(?P<u>__)
-(?P<sup>\^.*?\^)
-(?P<sub>,,[^,]{1,40},,)
-(?P<tt>\{\{\{.*?\}\}\})
-(?P<parser>(\{\{\{(#!.*|\s*$)))
-(?P<pre>(\{\{\{ ?|\}\}\}))
-(?P<small>(\~- ?|-\~))
-(?P<big>(\~\+ ?|\+\~))
-(?P<strike>(--\(|\)--))
-(?P<remark>(/\* ?| ?\*/))
-(?P<rule>-{4,})
-(?P<comment>^\#\#.*$)
-(?P<macro>\[\[(%%(macronames)s)(?:\(.*?\))?\]\])
-(?P<ol>%(ol_rule)s)
-(?P<dl>%(dl_rule)s)
-(?P<li>^\s+\*\s*)
-(?P<li_none>^\s+\.\s*)
-(?P<indent>^\s+)
-(?P<tableZ>\|\| $)
-(?P<table>(?:\|\|)+(?:<[^>]*?>)?(?!\|? $))
-(?P<heading>^\s*(?P<hmarker>=+)\s.*\s(?P=hmarker) $)
-(?P<interwiki>[A-Z][a-zA-Z]+\:(%(dq_string)s|([^\s'\"\:\<\|]([^\s%(punct)s]|([%(punct)s][^\s%(punct)s]))+)))
-(?P<word>%(word_rule)s)
-(?P<url_bracket>\[((%(url)s)\:|#|\:)[^\s\]]+(\s[^\]]+)?\])
-(?P<url>%(url_rule)s)
-(?P<email>[-\w._+]+\@[\w-]+(\.[\w-]+)+)
-(?P<smiley>(?<=\s)(%(smiley)s)(?=\s))
-(?P<smileyA>^(%(smiley)s)(?=\s))
-(?P<ent_symbolic>&[a-zA-Z]+;)
-(?P<ent>[<>&])
-(?P<wikiname_bracket>\[%(dq_string)s.*?\])
-(?P<tt_bt>`.*?`)"""  % {
+    # the big, fat, less ugly one ;)
+    # please be very careful: blanks and # must be escaped with \ !
+    scan_rules = ur"""
+(?P<emph_ibb>
+    '''''(?=[^']+''')  # italic on, bold on, ..., bold off
+)|(?P<emph_ibi>
+    '''''(?=[^']+'')  # italic on, bold on, ..., italic off
+)|(?P<emph_ib_or_bi>
+    '{5}(?=[^'])  # italic and bold or bold and italic
+)|(?P<emph>
+    '{2,3}  # italic or bold
+)|(?P<u>
+    __ # underline
+)|(?P<small>
+    (
+     (?P<small_on>\~-\ ?)  # small on (we eat a trailing blank if it is there)
+    |
+     (?P<small_off>-\~)  # small off
+    )
+)|(?P<big>
+    (
+     (?P<big_on>\~\+\ ?)  # big on (eat trailing blank)
+    |
+     (?P<big_off>\+\~)  # big off
+    )
+)|(?P<strike>
+    (
+     (?P<strike_on>--\()  # strike-through on
+    |
+     (?P<strike_off>\)--)  # strike-through off
+    )
+)|(?P<remark>
+    (
+     (?P<remark_on>/\*\ ?)  # inline remark on (eat trailing blank)
+    |
+     (?P<remark_off>\ ?\*/)  # off
+    )
+)|(?P<sup>
+    \^  # superscript on
+    (?P<sup_text>.*?)  # capture the text
+    \^  # off
+)|(?P<sub>
+    ,,  # subscript on
+    (?P<sub_text>[^,]{1,40})  # capture 1..40 chars of text
+    ,,  # off
+)|(?P<tt>
+    \{\{\{  # teletype on
+    (?P<tt_text>.*?)  # capture the text
+    \}\}\}  # off
+)|(?P<tt_bt>
+    `  # teletype (using a backtick) on
+    (?P<tt_bt_text>.*?)  # capture the text
+    `  # off
+)|(?P<interwiki>
+    (?P<interwiki_wiki>[A-Z][a-zA-Z]+)  # interwiki wiki name
+    \:
+    (?P<interwiki_page>
+     [^\s'\"\:\<\|]
+     (
+      [^\s%(punct)s]
+     |
+      (
+       [%(punct)s]
+       [^\s%(punct)s]
+      )
+     )+
+    )  # interwiki page name
+)|(?P<word>  # must come AFTER interwiki rule!
+    %(word_rule)s  # CamelCase wiki words
+)|(?P<link>
+    \[\[
+    (?P<link_target>.+?)\s*  # link target (eat trailing space)
+    (\|\s*(?P<link_args>.+?)?\s*)? # link description (usually text, optional, strip space)
+    \]\]
+)|
+%(transclude_rule)s
+|(?P<url>
+    %(url_rule)s
+)|(?P<email>
+    [-\w._+]+  # name
+    \@  # at
+    [\w-]+(\.[\w-]+)+  # server/domain
+)|(?P<smiley>
+    (^|(?<=\s))  # we require either beginning of line or some space before a smiley
+    (%(smiley)s)  # one of the smileys
+    (?=\s)  # we require some space after the smiley
+)|(?P<macro>
+    <<
+    (?P<macro_name>(%%(macronames)s))  # name of the macro (only existing ones will match)
+    (?:\((?P<macro_args>.*?)\))?  # optionally macro arguments
+    >>
+)|(?P<heading>
+    ^(?P<hmarker>=+)\s+  # some === at beginning of line, eat trailing blanks
+    (?P<heading_text>.*)  # capture heading text
+    \s+(?P=hmarker)\s$  # some === at end of line (matching amount as we have seen), eat blanks
+)|(?P<parser>
+    \{\{\{
+    (
+     \#!.*  # we have a parser name directly following
+    |
+     \s*$  # no parser name, eat whitespace
+    )
+)|(?P<pre>
+    (
+     \{\{\{\ ?  # pre on
+    |
+     \}\}\}  # off
+    )
+)|(?P<comment>
+    ^\#\#.*$  # src code comment, rest of line
+)|(?P<ol>
+    %(ol_rule)s  # ordered list
+)|(?P<dl>
+    %(dl_rule)s  # definition list
+)|(?P<li>
+    ^\s+\*\s*  # unordered list
+)|(?P<li_none>
+    ^\s+\.\s*  # unordered list, no bullets
+)|(?P<indent>
+    ^\s+  # indented by some spaces
+)|(?P<tableZ>
+    \|\|\ $  # the right end of a table row
+)|(?P<table>
+    (?:\|\|)+(?:<[^>]*?>)?(?!\|?\s$) # a table
+)|(?P<rule>
+    -{4,}  # hor. rule, min. 4 -
+)|(?P<entity>
+    &(
+      ([a-zA-Z]+)  # symbolic entity, like &uuml;
+      |
+      (\#(\d{1,5}|x[0-9a-fA-F]+))  # numeric entities, like &#42; or &#x42;
+     );
+)|(?P<sgml_entity>  # must come AFTER entity rule!
+    [<>&]  # needs special treatment for html/xml
+)"""  % {
 
-        'url': url_pattern,
+        'url_scheme': url_scheme,
+        'url_rule': url_rule,
         'punct': punct_pattern,
-        'dq_string': dq_string,
         'ol_rule': ol_rule,
         'dl_rule': dl_rule,
-        'url_rule': url_rule,
         'word_rule': word_rule,
+        'transclude_rule': transclude_rule,
         'smiley': u'|'.join([re.escape(s) for s in config.smileys])}
 
     # Don't start p before these
@@ -125,8 +318,8 @@
         self._ = request.getText
         self.cfg = request.cfg
         self.line_anchors = kw.get('line_anchors', True)
+        self.start_line = kw.get('start_line', 0)
         self.macro = None
-        self.start_line = kw.get('start_line', 0)
 
         # currently, there is only a single, optional argument to this parser and
         # (when given), it is used as class(es) for a div wrapping the formatter output
@@ -163,7 +356,8 @@
         self.list_indents = []
         self.list_types = []
 
-        self.formatting_rules = self.formatting_rules % {'macronames': u'|'.join(macro.getNames(self.cfg))}
+        # XXX TODO if we remove the runtime dependency, we can compile the scan_rules at module load time:
+        self.scan_rules = self.scan_rules % {'macronames': u'|'.join(macro.getNames(self.cfg))}
 
     def _close_item(self, result):
         #result.append("<!-- close item begin -->\n")
@@ -182,104 +376,65 @@
             result.append(self.formatter.definition_desc(0))
         #result.append("<!-- close item end -->\n")
 
-    def interwiki(self, target_and_text, **kw):
-        # TODO: maybe support [wiki:Page http://wherever/image.png] ?
-        scheme, rest = target_and_text.split(':', 1)
-        wikiname, pagename, text = wikiutil.split_wiki(rest)
-        if not text:
-            text = pagename
-        #self.request.log("interwiki: split_wiki -> %s.%s.%s" % (wikiname,pagename,text))
-
-        if wikiname.lower() == 'self': # [wiki:Self:LocalPage text] or [:LocalPage:text]
-            return self._word_repl(pagename, text)
-
-        # check for image URL, and possibly return IMG tag
-        if not kw.get('pretty_url', 0) and wikiutil.isPicture(pagename):
-            dummy, wikiurl, dummy, wikitag_bad = wikiutil.resolve_wiki(self.request, rest)
-            href = wikiutil.join_wiki(wikiurl, pagename)
-            #self.request.log("interwiki: join_wiki -> %s.%s.%s" % (wikiurl,pagename,href))
-            return self.formatter.image(src=href)
-
-        return (self.formatter.interwikilink(1, wikiname, pagename) +
-                self.formatter.text(text) +
-                self.formatter.interwikilink(0, wikiname, pagename))
-
-    def attachment(self, target_and_text, **kw):
-        """ This gets called on attachment URLs """
-        _ = self._
-        #self.request.log("attachment: target_and_text %s" % target_and_text)
-        scheme, fname, text = wikiutil.split_wiki(target_and_text)
-        if not text:
-            text = fname
-
-        if scheme == 'drawing':
-            return self.formatter.attachment_drawing(fname, text)
-
-        # check for image, and possibly return IMG tag (images are always inlined)
-        if not kw.get('pretty_url', 0) and wikiutil.isPicture(fname):
-            return self.formatter.attachment_image(fname)
-
-        # inline the attachment if it's major mimetype is text
-        mt = wikiutil.MimeType(filename=fname)
-        if scheme == 'inline':
-            if mt.major == 'text':
-                return self.formatter.attachment_inlined(fname, text)
-            else:
-                # use EmbedObject for other mimetypes
-                from MoinMoin.macro.EmbedObject import EmbedObject
-                from MoinMoin.action import AttachFile
-                if not mt is None:
-                    # reuse class tmp from Despam to define macro
-                    from MoinMoin.action.Despam import tmp
-                    macro = tmp()
-                    macro.request = self.request
-                    macro.formatter = self.request.html_formatter
-                    pagename = self.formatter.page.page_name
-                    url = AttachFile.getAttachUrl(pagename, fname, self.request, escaped=1)
-                    return self.formatter.rawHTML(EmbedObject.embed(EmbedObject(macro, wikiutil.escape(fname)), mt, url))
-
-        return (self.formatter.attachment_link(1, fname) +
-                self.formatter.text(text) +
-                self.formatter.attachment_link(0))
-
-    def _u_repl(self, word):
+    def _u_repl(self, word, groups):
         """Handle underline."""
         self.is_u = not self.is_u
         return self.formatter.underline(self.is_u)
 
-    def _strike_repl(self, word):
+    def _remark_repl(self, word, groups):
+        """Handle remarks."""
+        on = groups.get('remark_on')
+        if on and self.is_remark:
+            return self.formatter.text(word)
+        off = groups.get('remark_off')
+        if off and not self.is_remark:
+            return self.formatter.text(word)
+        self.is_remark = not self.is_remark
+        return self.formatter.span(self.is_remark, css_class='comment')
+    _remark_on_repl = _remark_repl
+    _remark_off_repl = _remark_repl
+
+    def _strike_repl(self, word, groups):
         """Handle strikethrough."""
-        # XXX we don't really enforce the correct sequence --( ... )-- here
+        on = groups.get('strike_on')
+        if on and self.is_strike:
+            return self.formatter.text(word)
+        off = groups.get('strike_off')
+        if off and not self.is_strike:
+            return self.formatter.text(word)
         self.is_strike = not self.is_strike
         return self.formatter.strike(self.is_strike)
+    _strike_on_repl = _strike_repl
+    _strike_off_repl = _strike_repl
 
-    def _remark_repl(self, word):
-        """Handle remarks."""
-        # XXX we don't really enforce the correct sequence /* ... */ here
-        self.is_remark = not self.is_remark
-        return self.formatter.span(self.is_remark, css_class='comment')
-
-    def _small_repl(self, word):
+    def _small_repl(self, word, groups):
         """Handle small."""
-        if word.strip() == '~-' and self.is_small:
+        on = groups.get('small_on')
+        if on and self.is_small:
             return self.formatter.text(word)
-        if word.strip() == '-~' and not self.is_small:
+        off = groups.get('small_off')
+        if off and not self.is_small:
             return self.formatter.text(word)
         self.is_small = not self.is_small
         return self.formatter.small(self.is_small)
+    _small_on_repl = _small_repl
+    _small_off_repl = _small_repl
 
-    def _big_repl(self, word):
+    def _big_repl(self, word, groups):
         """Handle big."""
-        if word.strip() == '~+' and self.is_big:
+        on = groups.get('big_on')
+        if on and self.is_big:
             return self.formatter.text(word)
-        if word.strip() == '+~' and not self.is_big:
+        off = groups.get('big_off')
+        if off and not self.is_big:
             return self.formatter.text(word)
         self.is_big = not self.is_big
         return self.formatter.big(self.is_big)
+    _big_on_repl = _big_repl
+    _big_off_repl = _big_repl
 
-    def _emph_repl(self, word):
+    def _emph_repl(self, word, groups):
         """Handle emphasis, i.e. '' and '''."""
-        ## print "#", self.is_b, self.is_em, "#"
         if len(word) == 3:
             self.is_b = not self.is_b
             if self.is_em and self.is_b:
@@ -291,7 +446,7 @@
                 self.is_em = 2
             return self.formatter.emphasis(self.is_em)
 
-    def _emph_ibb_repl(self, word):
+    def _emph_ibb_repl(self, word, groups):
         """Handle mixed emphasis, i.e. ''''' followed by '''."""
         self.is_b = not self.is_b
         self.is_em = not self.is_em
@@ -299,7 +454,7 @@
             self.is_b = 2
         return self.formatter.emphasis(self.is_em) + self.formatter.strong(self.is_b)
 
-    def _emph_ibi_repl(self, word):
+    def _emph_ibi_repl(self, word, groups):
         """Handle mixed emphasis, i.e. ''''' followed by ''."""
         self.is_b = not self.is_b
         self.is_em = not self.is_em
@@ -307,9 +462,8 @@
             self.is_em = 2
         return self.formatter.strong(self.is_b) + self.formatter.emphasis(self.is_em)
 
-    def _emph_ib_or_bi_repl(self, word):
+    def _emph_ib_or_bi_repl(self, word, groups):
         """Handle mixed emphasis, exactly five '''''."""
-        ## print "*", self.is_b, self.is_em, "*"
         b_before_em = self.is_b > self.is_em > 0
         self.is_b = not self.is_b
         self.is_em = not self.is_em
@@ -318,170 +472,274 @@
         else:
             return self.formatter.emphasis(self.is_em) + self.formatter.strong(self.is_b)
 
-    def _sup_repl(self, word):
+    def _sup_repl(self, word, groups):
         """Handle superscript."""
-        return self.formatter.sup(1) + \
-            self.formatter.text(word[1:-1]) + \
-            self.formatter.sup(0)
+        text = groups.get('sup_text', '')
+        return (self.formatter.sup(1) +
+                self.formatter.text(text) +
+                self.formatter.sup(0))
+    _sup_text_repl = _sup_repl
 
-    def _sub_repl(self, word):
+    def _sub_repl(self, word, groups):
         """Handle subscript."""
-        return self.formatter.sub(1) + \
-            self.formatter.text(word[2:-2]) + \
-            self.formatter.sub(0)
+        text = groups.get('sub_text', '')
+        return (self.formatter.sub(1) +
+               self.formatter.text(text) +
+               self.formatter.sub(0))
+    _sub_text_repl = _sub_repl
 
+    def _tt_repl(self, word, groups):
+        """Handle inline code."""
+        tt_text = groups.get('tt_text', '')
+        return (self.formatter.code(1) +
+                self.formatter.text(tt_text) +
+                self.formatter.code(0))
+    _tt_text_repl = _tt_repl
 
-    def _rule_repl(self, word):
+    def _tt_bt_repl(self, word, groups):
+        """Handle backticked inline code."""
+        tt_bt_text = groups.get('tt_bt_text', '')
+        return (self.formatter.code(1, css="backtick") +
+                self.formatter.text(tt_bt_text) +
+                self.formatter.code(0))
+    _tt_bt_text_repl = _tt_bt_repl
+
+    def _rule_repl(self, word, groups):
         """Handle sequences of dashes."""
         result = self._undent() + self._closeP()
         if len(word) <= 4:
-            result = result + self.formatter.rule()
+            result += self.formatter.rule()
         else:
             # Create variable rule size 1 - 6. Actual size defined in css.
             size = min(len(word), 10) - 4
-            result = result + self.formatter.rule(size)
+            result += self.formatter.rule(size)
         return result
 
-    def _word_repl(self, word, text=None):
+    def _interwiki_repl(self, word, groups):
+        """Handle InterWiki links."""
+        wiki = groups.get('interwiki_wiki')
+        page = groups.get('interwiki_page')
+
+        wikitag_bad = wikiutil.resolve_interwiki(self.request, wiki, page)[3]
+        if wikitag_bad:
+            text = groups.get('interwiki')
+            return self.formatter.text(text)
+        else:
+            return (self.formatter.interwikilink(1, wiki, page) +
+                    self.formatter.text(page) +
+                    self.formatter.interwikilink(0, wiki, page))
+    _interwiki_wiki_repl = _interwiki_repl
+    _interwiki_page_repl = _interwiki_repl
+
+    def _word_repl(self, word, groups):
         """Handle WikiNames."""
-
+        bang = groups.get('word_bang')
+        if bang:
+            # self.cfg.bang_meta:
+            # handle !NotWikiNames
+            return self.formatter.nowikiword(word)
+        orig_word = word
+        name = groups.get('word_name')
+        parent_prefix = groups.get('word_parent_prefix')
+        current_page = self.formatter.page.page_name
         # check for parent links
         # !!! should use wikiutil.AbsPageName here, but setting `text`
         # correctly prevents us from doing this for now
-        if word.startswith(wikiutil.PARENT_PREFIX):
-            if not text:
-                text = word
-            word = '/'.join([x for x in self.formatter.page.page_name.split('/')[:-1] + [word[wikiutil.PARENT_PREFIX_LEN:]] if x])
-        if not text:
-            # if a simple, self-referencing link, emit it as plain text
-            if word == self.formatter.page.page_name:
-                return self.formatter.text(word)
-            text = word
-        if word.startswith(wikiutil.CHILD_PREFIX):
-            word = self.formatter.page.page_name + '/' + word[wikiutil.CHILD_PREFIX_LEN:]
-
-        # handle anchors
-        parts = word.split("#", 1)
-        anchor = ""
-        if len(parts) == 2:
-            word, anchor = parts
-
-        return (self.formatter.pagelink(1, word, anchor=anchor) +
-                self.formatter.text(text) +
-                self.formatter.pagelink(0, word))
-
-    def _notword_repl(self, word):
-        """Handle !NotWikiNames."""
-        return self.formatter.nowikiword(word[1:])
-
-    def _interwiki_repl(self, word):
-        """Handle InterWiki links."""
-        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, word)
-        if wikitag_bad:
-            return self.formatter.text(word)
+        #if parent_prefix:
+        #    name = '/'.join([x for x in current_page.split('/')[:-1] + [name] if x])
+        #elif name.startswith(self.CHILD_PREFIX):
+        #    name = current_page + '/' + name[self.CHILD_PREFIX_LEN:]
+        name = wikiutil.AbsPageName(self.request, current_page, name)
+        # if a simple, self-referencing link, emit it as plain text
+        if name == current_page:
+            return self.formatter.text(orig_word)
         else:
-            return self.interwiki("wiki:" + word)
-
-    def _url_repl(self, word):
-        """Handle literal URLs including inline images."""
-        scheme = word.split(":", 1)[0]
-
-        if scheme == "wiki":
-            return self.interwiki(word)
-
-        if scheme in self.attachment_schemas:
-            return self.attachment(word)
-
-        if wikiutil.isPicture(word):
-            word = wikiutil.mapURL(self.request, word)
-            # Get image name http://here.com/dir/image.gif -> image
-            name = word.split('/')[-1]
-            name = ''.join(name.split('.')[:-1])
-            return self.formatter.image(src=word, alt=name)
-        else:
-            return (self.formatter.url(1, word, css=scheme) +
-                    self.formatter.text(word) +
-                    self.formatter.url(0))
+            # handle anchors
+            parts = name.split("#", 1)
+            anchor = ""
+            if len(parts) == 2:
+                name, anchor = parts
+            return (self.formatter.pagelink(1, name, anchor=anchor) +
+                    self.formatter.text(orig_word) +
+                    self.formatter.pagelink(0, name))
+    _word_bang_repl = _word_repl
+    _word_parent_prefix_repl = _word_repl
+    _word_name_repl = _word_repl
 
-    def _wikiname_bracket_repl(self, text):
-        """Handle special-char wikinames with link text, like:
-           ["Jim O'Brian" Jim's home page] or ["Hello ""world""!" a page with doublequotes]
-        """
-        word = text[1:-1] # strip brackets
-        empty, target, linktext = wikiutil.split_wiki(':%s' % word)
-        if target:
-            linktext = linktext.strip()
-            return self._word_repl(target, linktext)
-        else:
-            return self.formatter.text(text)
-
-    def _url_bracket_repl(self, word):
-        """Handle bracketed URLs."""
-        word = word[1:-1] # strip brackets
-
-        # Local extended link? [:page name:link text] XXX DEPRECATED
-        if word[0] == ':':
-            words = word[1:].split(':', 1)
-            if len(words) == 1:
-                words = words * 2
-            target_and_text = 'wiki:Self:%s %s' % (wikiutil.quoteName(words[0]), words[1])
-            return self.interwiki(target_and_text, pretty_url=1)
+    def _url_repl(self, word, groups):
+        """Handle literal URLs."""
+        scheme = groups.get('url_scheme', 'http')
+        target = groups.get('url_target', '')
+        return (self.formatter.url(1, target, css=scheme) +
+                self.formatter.text(target) +
+                self.formatter.url(0))
+    _url_target_repl = _url_repl
+    _url_scheme_repl = _url_repl
 
-        scheme_and_rest = word.split(":", 1)
-        if len(scheme_and_rest) == 1: # no scheme
-            # Traditional split on space
-            words = word.split(None, 1)
-            if len(words) == 1:
-                words = words * 2
 
-            if words[0].startswith('#'): # anchor link
-                res = []
-                res.append(self.formatter.anchorlink(1, words[0][1:]))
-                res.append(self.formatter.text(words[1]))
-                res.append(self.formatter.anchorlink(0))
-                return ''.join(res)
+    def _transclude_repl(self, word, groups):
+        """Handles transcluding content, usually embedding images."""
+        target = groups.get('transclude_target', '').strip()
+        args = (groups.get('transclude_args', '') or '').strip()
+        target = wikiutil.url_unquote(target, want_unicode=True)
+        m = self.link_target_re.match(target)
+        ma = self.transclude_desc_re.match(args)
+        desc = None
+        if ma:
+            if ma.group('simple_text'):
+                desc = ma.group('simple_text')
+                desc = wikiutil.escape(desc)
+        if m:
+            if m.group('extern_addr'):
+                scheme = m.group('extern_scheme')
+                target = m.group('extern_addr')
+                if not desc:
+                    desc = wikiutil.escape(target)
+                if scheme.startswith('http'): # can also be https
+                    # currently only supports ext. image inclusion
+                    return self.formatter.image(src=target, alt=desc, title=desc, css_class='external_image')
+
+            elif m.group('attach_scheme'):
+                scheme = m.group('attach_scheme')
+                url = wikiutil.url_unquote(m.group('attach_addr'), want_unicode=True)
+                if not desc:
+                    desc = wikiutil.escape(url)
+                if scheme == 'attachment':
+                    mt = wikiutil.MimeType(filename=url)
+                    if mt.major == 'text':
+                        return self.formatter.attachment_inlined(url, desc)
+                    elif mt.major == 'image':
+                        return self.formatter.attachment_image(url, alt=desc, title=desc, css_class='image')
+                    else:
+                        # use EmbedObject for other mimetypes
+                        from MoinMoin.macro.EmbedObject import EmbedObject
+                        from MoinMoin.action import AttachFile
+                        if mt is not None:
+                            # reuse class tmp from Despam to define macro
+                            from MoinMoin.action.Despam import tmp
+                            macro = tmp()
+                            macro.request = self.request
+                            macro.formatter = self.request.html_formatter
+                            pagename = self.formatter.page.page_name
+                            href = AttachFile.getAttachUrl(pagename, url, self.request, escaped=1)
+                            return self.formatter.rawHTML(EmbedObject.embed(EmbedObject(macro, wikiutil.escape(url)), mt, href))
+                elif scheme == 'drawing':
+                    return self.formatter.attachment_drawing(url, desc)
+
+            elif m.group('page_name'): # TODO
+                page_name = m.group('page_name')
+                return u"Error: <<Include(%s,%s)>> emulation missing..." % (page_name, args)
+
+            elif m.group('inter_wiki'): # TODO
+                wiki_name = m.group('inter_wiki')
+                page_name = m.group('inter_page')
+                return u"Error: <<RemoteInclude(%s:%s,%s)>> still missing." % (wiki_name, page_name, args)
+
+            else:
+                if not desc:
+                    desc = target
+                return self.formatter.text('[[%s|%s]]' % (target, desc))
+        return word +'???'
+    _transclude_target_repl = _transclude_repl
+    _transclude_args_repl = _transclude_repl
+
+    def _link_description(self, desc, target='', default_text=''):
+        """ parse a string <desc> valid as link description (text, transclusion, ...)
+            and return formatted content.
+
+            @param desc: the link description to parse
+            @param default_text: use this text (formatted as text) if parsing
+                                 desc returns nothing.
+            @param target: target of the link (as readable markup) - used for
+                           transcluded image's description
+        """
+        m = self.link_desc_re.match(desc)
+        if m:
+            if m.group('simple_text'):
+                desc = m.group('simple_text')
+                desc = wikiutil.escape(desc)
+                desc = self.formatter.text(desc)
+            elif m.group('transclude'):
+                groupdict = m.groupdict()
+                if groupdict.get('transclude_args') is None:
+                    # if transcluded obj (image) has no description, use target for it
+                    groupdict['transclude_args'] = target
+                desc = m.group('transclude')
+                desc = self._transclude_repl(desc, groupdict)
         else:
-            scheme, rest = scheme_and_rest
-            if scheme == "wiki":
-                return self.interwiki(word, pretty_url=1)
-            if scheme in self.attachment_schemas:
-                return self.attachment(word, pretty_url=1)
-
-            words = word.split(None, 1)
-            if len(words) == 1:
-                words = words * 2
+            desc = default_text
+            if desc:
+                desc = self.formatter.text(desc)
+        return desc
 
-        if wikiutil.isPicture(words[1]) and re.match(self.url_rule, words[1]):
-            return (self.formatter.url(1, words[0], css='external', do_escape=0) +
-                    self.formatter.image(title=words[0], alt=words[0], src=words[1]) +
-                    self.formatter.url(0))
-        else:
-            return (self.formatter.url(1, words[0], css=scheme, do_escape=0) +
-                    self.formatter.text(words[1]) +
-                    self.formatter.url(0))
+    def _link_repl(self, word, groups):
+        """Handle [[target|text]] links."""
+        target = groups.get('link_target', '')
+        desc = (groups.get('link_args', '') or '').strip()
+        mt = self.link_target_re.match(target)
+        if mt:
+            if mt.group('page_name'):
+                page_name = mt.group('page_name')
+                # handle relative links
+                if page_name.startswith(self.CHILD_PREFIX):
+                    page_name = self.formatter.page.page_name + '/' + page_name[self.CHILD_PREFIX_LEN:] # XXX use func
+                # handle anchors
+                try:
+                    page_name, anchor = page_name.split("#", 1)
+                except ValueError:
+                    anchor = ""
+                if not page_name:
+                    page_name = self.formatter.page.page_name
+                return (self.formatter.pagelink(1, page_name, anchor=anchor) +
+                        self._link_description(desc, target, page_name) +
+                        self.formatter.pagelink(0, page_name))
 
-    def _email_repl(self, word):
+            elif mt.group('extern_addr'):
+                scheme = mt.group('extern_scheme')
+                target = mt.group('extern_addr')
+                return (self.formatter.url(1, target, css=scheme) +
+                        self._link_description(desc, target, target) +
+                        self.formatter.url(0))
+
+            elif mt.group('inter_wiki'):
+                wiki_name = mt.group('inter_wiki')
+                page_name = mt.group('inter_page')
+                wikitag_bad = wikiutil.resolve_interwiki(self.request, wiki_name, page_name)[3]
+                return (self.formatter.interwikilink(1, wiki_name, page_name) +
+                        self._link_description(desc, target, page_name) +
+                        self.formatter.interwikilink(0, wiki_name, page_name))
+
+            elif mt.group('attach_scheme'):
+                scheme = mt.group('attach_scheme')
+                url = wikiutil.url_unquote(mt.group('attach_addr'), want_unicode=True)
+                if scheme == 'attachment':
+                    return (self.formatter.attachment_link(1, url, title=desc) +
+                            self._link_description(desc, target, url) +
+                            self.formatter.attachment_link(0))
+                elif scheme == 'drawing':
+                    return self.formatter.attachment_drawing(url, desc, title=desc, alt=desc)
+            else:
+                if desc:
+                    desc = '|' + desc
+                return self.formatter.text('[[%s%s]]' % (target, desc))
+    _link_target_repl = _link_repl
+    _link_args_repl = _link_repl
+
+    def _email_repl(self, word, groups):
         """Handle email addresses (without a leading mailto:)."""
-        return (self.formatter.url(1, "mailto:" + word, css='mailto') +
+        return (self.formatter.url(1, "mailto:%s" % word, css='mailto') +
                 self.formatter.text(word) +
                 self.formatter.url(0))
 
-    def _ent_repl(self, word):
+    def _sgml_entity_repl(self, word, groups):
         """Handle SGML entities."""
         return self.formatter.text(word)
-        #return {'&': '&amp;',
-        #        '<': '&lt;',
-        #        '>': '&gt;'}[word]
 
-    def _ent_numeric_repl(self, word):
-        """Handle numeric (decimal and hexadecimal) SGML entities."""
+    def _entity_repl(self, word, groups):
+        """Handle numeric (decimal and hexadecimal) and symbolic SGML entities."""
         return self.formatter.rawHTML(word)
 
-    def _ent_symbolic_repl(self, word):
-        """Handle symbolic SGML entities."""
-        return self.formatter.rawHTML(word)
-
-    def _indent_repl(self, match):
+    def _indent_repl(self, match, groups):
         """Handle pure indentation (no - * 1. markup)."""
         result = []
         if not (self.in_li or self.in_dd):
@@ -493,7 +751,7 @@
             result.append(self.formatter.listitem(1, css_class=css_class, style="list-style-type:none"))
         return ''.join(result)
 
-    def _li_none_repl(self, match):
+    def _li_none_repl(self, match, groups):
         """Handle type=none (" .") lists."""
         result = []
         self._close_item(result)
@@ -504,7 +762,7 @@
         result.append(self.formatter.listitem(1, css_class=css_class, style="list-style-type:none"))
         return ''.join(result)
 
-    def _li_repl(self, match):
+    def _li_repl(self, match, groups):
         """Handle bullet (" *") lists."""
         result = []
         self._close_item(result)
@@ -515,11 +773,11 @@
         result.append(self.formatter.listitem(1, css_class=css_class))
         return ''.join(result)
 
-    def _ol_repl(self, match):
+    def _ol_repl(self, match, groups):
         """Handle numbered lists."""
-        return self._li_repl(match)
+        return self._li_repl(match, groups)
 
-    def _dl_repl(self, match):
+    def _dl_repl(self, match, groups):
         """Handle definition lists."""
         result = []
         self._close_item(result)
@@ -609,19 +867,6 @@
         self.list_types = []
         return ''.join(result)
 
-    def _tt_repl(self, word):
-        """Handle inline code."""
-        return self.formatter.code(1) + \
-            self.formatter.text(word[3:-3]) + \
-            self.formatter.code(0)
-
-    def _tt_bt_repl(self, word):
-        """Handle backticked inline code."""
-        # if len(word) == 2: return "" // removed for FCK editor
-        return self.formatter.code(1, css="backtick") + \
-            self.formatter.text(word[1:-1]) + \
-            self.formatter.code(0)
-
     def _getTableAttrs(self, attrdef):
         # skip "|" and initial "<"
         while attrdef and attrdef[0] == "|":
@@ -711,7 +956,7 @@
         #self.request.log("parseAttributes returned %r" % attr)
         return attr, msg
 
-    def _tableZ_repl(self, word):
+    def _tableZ_repl(self, word, groups):
         """Handle table row end."""
         if self.in_table:
             result = ''
@@ -723,7 +968,7 @@
         else:
             return self.formatter.text(word)
 
-    def _table_repl(self, word):
+    def _table_repl(self, word, groups):
         """Handle table cell separator."""
         if self.in_table:
             result = []
@@ -757,24 +1002,20 @@
         else:
             return self.formatter.text(word)
 
-    def _heading_repl(self, word):
+    def _heading_repl(self, word, groups):
         """Handle section headings."""
-        h = word.strip()
-        level = 1
-        while h[level:level+1] == '=':
-            level += 1
-        depth = min(5, level)
-
-        title_text = h[level:-level].strip()
-
+        heading_text = groups.get('heading_text', '').strip()
+        depth = min(len(groups.get('hmarker')), 5)
         return ''.join([
             self._closeP(),
-            self.formatter.heading(1, depth, id=title_text),
-            self.formatter.text(title_text),
+            self.formatter.heading(1, depth, id=heading_text),
+            self.formatter.text(heading_text),
             self.formatter.heading(0, depth),
         ])
+    _heading_text_repl = _heading_repl
+    _hmarker_repl = _heading_repl
 
-    def _parser_repl(self, word):
+    def _parser_repl(self, word, groups):
         """Handle parsed code displays."""
         if word.startswith('{{{'):
             self.in_nested_pre = 1
@@ -807,7 +1048,7 @@
             self.in_pre = 'search_parser'
             return ''
 
-    def _pre_repl(self, word):
+    def _pre_repl(self, word, groups):
         """Handle code displays."""
         word = word.strip()
         if word == '{{{' and not self.in_pre:
@@ -826,13 +1067,11 @@
             return self.formatter.text(word)
         return self.formatter.text(word)
 
-    def _smiley_repl(self, word):
+    def _smiley_repl(self, word, groups):
         """Handle smileys."""
         return self.formatter.smiley(word)
 
-    _smileyA_repl = _smiley_repl
-
-    def _comment_repl(self, word):
+    def _comment_repl(self, word, groups):
         # if we are in a paragraph, we must close it so that normal text following
         # in the line below the comment will reopen a new paragraph.
         if self.formatter.in_p:
@@ -845,21 +1084,18 @@
             return self.formatter.paragraph(0)
         return ''
 
-    def _macro_repl(self, word):
-        """Handle macros ([[macroname]])."""
-        macro_name = word[2:-2]
+    def _macro_repl(self, word, groups):
+        """Handle macros (<<macroname>>)."""
+        macro_name = groups.get('macro_name')
+        macro_args = groups.get('macro_args')
         self.inhibit_p = 0 # 1 fixes UserPreferences, 0 fixes paragraph formatting for macros
 
-        # check for arguments
-        args = None
-        if macro_name.count("("):
-            macro_name, args = macro_name.split('(', 1)
-            args = args[:-1]
-
         # create macro instance
         if self.macro is None:
             self.macro = macro.Macro(self)
-        return self.formatter.macro(self.macro, macro_name, args)
+        return self.formatter.macro(self.macro, macro_name, macro_args)
+    _macro_name_repl = _macro_repl
+    _macro_args_repl = _macro_repl
 
     def scan(self, scan_re, line, inhibit_p=False):
         """ Scans one line
@@ -898,6 +1134,15 @@
             result.append(self.formatter.text(line[lastpos:]))
         return u''.join(result)
 
+    def _replace(self, match):
+        """ Same as replace() but with no magic """
+        for name, text in match.groupdict().iteritems():
+            if text is not None:
+                # Get replace method and replace text
+                replace_func = getattr(self, '_%s_repl' % name)
+                result = replace_func(text, match.groupdict())
+                return result
+
     def replace(self, match, inhibit_p=False):
         """ Replace match using type name """
         result = []
@@ -911,8 +1156,8 @@
                     result.append(self.formatter.paragraph(1, css_class="line891"))
 
                 # Get replace method and replace hit
-                replace = getattr(self, '_' + type + '_repl')
-                result.append(replace(hit))
+                replace_func = getattr(self, '_%s_repl' % type)
+                result.append(replace_func(hit, match.groupdict()))
                 return ''.join(result)
         else:
             # We should never get here
@@ -940,21 +1185,11 @@
         self.hilite_re = self.formatter.page.hilite_re
 
         # prepare regex patterns
-        rules = self.formatting_rules.replace('\n', '|')
-        if self.cfg.bang_meta:
-            rules = ur'(?P<notword>!%(word_rule)s)|%(rules)s' % {
-                'word_rule': self.word_rule,
-                'rules': rules,
-            }
-        pre_rules = self.pre_formatting_rules.replace('\n', '|')
-        self.request.clock.start('compile_huge_and_ugly')
-        scan_re = re.compile(rules, re.UNICODE)
-        pre_scan_re = re.compile(pre_rules, re.UNICODE)
-        number_re = re.compile(self.ol_rule, re.UNICODE)
-        term_re = re.compile(self.dl_rule, re.UNICODE)
+        self.request.clock.start('compile_huge_and_pretty')
+        scan_re = re.compile(self.scan_rules, re.UNICODE|re.VERBOSE)
         indent_re = re.compile(ur"^\s*", re.UNICODE)
         eol_re = re.compile(r'\r?\n', re.UNICODE)
-        self.request.clock.stop('compile_huge_and_ugly')
+        self.request.clock.stop('compile_huge_and_pretty')
 
         # get text and replace TABs
         rawtext = self.raw.expandtabs()
@@ -971,7 +1206,7 @@
 
         # Main loop
         for line in self.lines:
-            if ']][[' in line.replace(' ', ''):
+            if '>><<' in line.replace(' ', ''):
                 self.no_862 = True
 
             self.line_anchor_printed = 0
@@ -1083,7 +1318,7 @@
                 numtype = None
                 numstart = None
                 if indlen:
-                    match = number_re.match(line)
+                    match = self.ol_re.match(line)
                     if match:
                         numtype, numstart = match.group(0).strip().split('.')
                         numtype = numtype[0]
@@ -1095,7 +1330,7 @@
 
                         indtype = "ol"
                     else:
-                        match = term_re.match(line)
+                        match = self.dl_re.match(line)
                         if match:
                             indtype = "dl"
 
@@ -1133,7 +1368,7 @@
                     self.in_table = 0
 
             # Scan line, format and write
-            scanning_re = self.in_pre and pre_scan_re or scan_re
+            scanning_re = self.in_pre and self.pre_scan_re or scan_re
             if '{{{' in line:
                 self.in_nested_pre += 1
             formatted_line = self.scan(scanning_re, line, inhibit_p=inhibit_p)
@@ -1161,3 +1396,5 @@
             self.parser = wikiutil.searchAndImportPlugin(self.request.cfg, "parser", name)
         except wikiutil.PluginMissingError:
             self.parser = None
+
+
--- a/MoinMoin/parser/text_rst.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/parser/text_rst.py	Tue Aug 21 15:47:56 2007 +0200
@@ -358,7 +358,8 @@
                 if not [i for i in node.children if i.__class__ == docutils.nodes.image]:
                     node['classes'].append(prefix)
             elif prefix == 'wiki':
-                wikitag, wikiurl, wikitail, err = wikiutil.resolve_wiki(self.request, link)
+                wiki_name, page_name = wikiutil.split_interwiki(link)
+                wikitag, wikiurl, wikitail, err = wikiutil.resolve_interwiki(self.request, wiki_name, page_name)
                 wikiurl = wikiutil.mapURL(self.request, wikiurl)
                 node['refuri'] = wikiutil.join_wiki(wikiurl, wikitail)
                 # Only add additional class information if the reference does
--- a/MoinMoin/request/__init__.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/request/__init__.py	Tue Aug 21 15:47:56 2007 +0200
@@ -1206,11 +1206,13 @@
                 pagetrail = self.user.getTrail()
                 if pagetrail:
                     # Redirect to last page visited
-                    if ":" in pagetrail[-1]:
-                        wikitag, wikiurl, wikitail, error = wikiutil.resolve_wiki(self, pagetrail[-1])
+                    last_visited = pagetrail[-1]
+                    wikiname, pagename = wikiutik.split_interwiki(last_visited)
+                    if wikiname != 'Self':
+                        wikitag, wikiurl, wikitail, error = wikiutil.resolve_interwiki(self, wikiname, pagename)
                         url = wikiurl + wikiutil.quoteWikinameURL(wikitail)
                     else:
-                        url = Page(self, pagetrail[-1]).url(self, relative=False)
+                        url = Page(self, pagename).url(self, relative=False)
                 else:
                     # Or to localized FrontPage
                     url = wikiutil.getFrontPage(self).url(self, relative=False)
--- a/MoinMoin/script/migration/_conv160.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/script/migration/_conv160.py	Tue Aug 21 15:47:56 2007 +0200
@@ -1,6 +1,6 @@
 # -*- coding: iso-8859-1 -*-
 """
-    MoinMoin - migration from base rev 105xxyy
+    MoinMoin - migration from 1.5.8 to 1.6.0 (creole link style)
 
     What it should do when it is ready:
 
--- a/MoinMoin/script/migration/_conv160_wiki.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/script/migration/_conv160_wiki.py	Tue Aug 21 15:47:56 2007 +0200
@@ -1,6 +1,7 @@
 # -*- coding: iso-8859-1 -*-
 """
-    MoinMoin - convert content in wiki markup
+    MoinMoin - convert content in 1.5.8 wiki markup to 1.6.0 style
+               by using a modified 1.5.8 parser as translator.
 
     Assuming we have this "renames" map:
     -------------------------------------------------------
@@ -9,13 +10,13 @@
 
     Markup transformations needed:
     -------------------------------------------------------
-    ["some_page"]           -> ["some page"] # renamed
-    [:some_page:some text]  -> ["some page" some text] # NEW: free link with link text
-    [:page:text]            -> ["page" text] # NEW: free link with link text
+    ["some_page"]           -> [[some page]] # renamed
+    [:some_page:some text]  -> [[some page|some text]]
+    [:page:text]            -> [[page|text]]
                                (with a page not being renamed)
 
-    attachment:with%20blank.txt -> attachment:"with blank.txt"
-    attachment:some_page/with%20blank.txt -> attachment:"some page/with blank.txt"
+    attachment:with%20blank.txt -> [[attachment:with blank.txt]]
+    attachment:some_page/with%20blank.txt -> [[attachment:some page/with blank.txt]]
     The attachment processing should also urllib.unquote the filename (or at
     least replace %20 by space) and put it into "quotes" if it contains spaces.
 
@@ -24,21 +25,77 @@
     @license: GNU GPL, see COPYING for details.
 """
 
-import re, codecs
+import re
+
 from MoinMoin import i18n
-i18n.wikiLanguages = lambda: []
-from MoinMoin import config, wikiutil
-from MoinMoin.parser.text_moin_wiki import Parser
+i18n.wikiLanguages = lambda: {}
+
+from MoinMoin import config, wikiutil, macro
 from MoinMoin.action import AttachFile
+from MoinMoin.Page import Page
+
+from text_moin158_wiki import Parser
+
+def convert_wiki(request, pagename, intext, renames):
+    """ Convert content written in wiki markup """
+    noeol = False
+    if not intext.endswith('\r\n'):
+        intext += '\r\n'
+        noeol = True
+    c = Converter(request, pagename, intext, renames)
+    result = request.redirectedOutput(c.convert, request)
+    if noeol and result.endswith('\r\n'):
+        result = result[:-2]
+    return result
+
 
 class Converter(Parser):
-    def __init__(self, pagename, raw, renames):
-        self.request = None
+    def __init__(self, request, pagename, raw, renames):
         self.pagename = pagename
         self.raw = raw
         self.renames = renames
-        self.in_pre = False
+        self.request = request
         self._ = None
+        self.in_pre = 0
+
+        self.formatting_rules = self.formatting_rules % {'macronames': u'|'.join(macro.getNames(self.request.cfg))}
+
+    # no change
+
+    def return_word(self, word):
+        return word
+    _emph_repl = return_word
+    _emph_ibb_repl = return_word
+    _emph_ibi_repl = return_word
+    _emph_ib_or_bi_repl = return_word
+    _u_repl = return_word
+    _strike_repl = return_word
+    _sup_repl = return_word
+    _sub_repl = return_word
+    _small_repl = return_word
+    _big_repl = return_word
+    _tt_repl = return_word
+    _tt_bt_repl = return_word
+    _remark_repl = return_word
+    _table_repl = return_word
+    _tableZ_repl = return_word
+    _rule_repl = return_word
+    _smiley_repl = return_word
+    _smileyA_repl = return_word
+    _ent_repl = return_word
+    _ent_numeric_repl = return_word
+    _ent_symbolic_repl = return_word
+    _heading_repl = return_word
+    _email_repl = return_word
+    _notword_repl = return_word
+    _indent_repl = return_word
+    _li_none_repl = return_word
+    _li_repl = return_word
+    _ol_repl = return_word
+    _dl_repl = return_word
+    _comment_repl = return_word
+
+    # translate pagenames using pagename translation map
 
     def _replace(self, key):
         """ replace a item_name if it is in the renames dict
@@ -59,75 +116,6 @@
             pass # TODO we have to fix the (absolute) new_name to be a relative name (as it was before)
         return new_name
 
-    def return_word(self, word):
-        return word
-    _remark_repl = return_word
-    _table_repl = return_word
-    _tableZ_repl = return_word
-    _emph_repl = return_word
-    _emph_ibb_repl = return_word
-    _emph_ibi_repl = return_word
-    _emph_ib_or_bi_repl = return_word
-    _u_repl = return_word
-    _strike_repl = return_word
-    _sup_repl = return_word
-    _sub_repl = return_word
-    _small_repl = return_word
-    _big_repl = return_word
-    _tt_repl = return_word
-    _tt_bt_repl = return_word
-    _notword_repl = return_word
-    _rule_repl = return_word
-    _smiley_repl = return_word
-    _smileyA_repl = return_word
-    _ent_repl = return_word
-    _ent_numeric_repl = return_word
-    _ent_symbolic_repl = return_word
-    _heading_repl = return_word
-    _email_repl = return_word
-    _word_repl = return_word
-    _indent_repl = return_word
-    _li_none_repl = return_word
-    _li_repl = return_word
-    _ol_repl = return_word
-    _dl_repl = return_word
-    _comment_repl = return_word
-
-    # PRE SECTION HANDLING ---------------------------------------------------
-
-    def _pre_repl(self, word):
-        origw = word
-        word = word.strip()
-        if word == '{{{' and not self.in_pre:
-            self.in_pre = True
-            return origw
-        elif word == '}}}' and self.in_pre:
-            self.in_pre = False
-            return origw
-        return word
-
-    def _parser_repl(self, word):
-        origw = word
-        if word.startswith('{{{'):
-            word = word[3:]
-
-        s_word = word.strip()
-        self.in_pre = True
-        return origw
-
-    def _macro_repl(self, word):
-        # XXX later check whether some to be renamed pagename is used as macro param
-        return word
-
-    # LINKS ------------------------------------------------------------------
-    def _intelli_quote(self, name):
-        quote_triggers = u''' "'()[]''' # u''' "\'}]|:,.()?!''' # see also wiki parser
-        quote_it = [True for c in quote_triggers if c in name]
-        if quote_it:
-            return wikiutil.quoteName(name)
-        else:
-            return name
-
     def _replace_target(self, target):
         target_and_anchor = target.split('#', 1)
         if len(target_and_anchor) > 1:
@@ -138,34 +126,30 @@
             target = self._replace(('PAGE', target))
             return target
 
-    def interwiki(self, target_and_text, **kw):
-        scheme, rest = target_and_text.split(':', 1)
-        wikiname, pagename, text = wikiutil.split_wiki(rest)
-        if wikiname in ('Self', self.request.cfg.interwikiname): # our wiki
-            pagename = self._replace(('PAGE', pagename))
-        #pagename = pagename.replace('_', ' ') # better not touch this
-        pagename = wikiutil.url_unquote(pagename)
-        return scheme, wikiname, pagename, text
+    # markup conversion
 
-    def attachment(self, target_and_text, **kw):
-        """ This gets called on attachment URLs """
-        _ = self._
-        scheme, fname, text = wikiutil.split_wiki(target_and_text)
-        pagename, fname = AttachFile.absoluteName(fname, self.pagename)
-        from_this_page = pagename == self.pagename
-        fname = self._replace(('FILE', pagename, fname))
-        if '%20' in fname:
-            fname = fname.replace('%20', ' ')
-        fname = self._replace(('FILE', pagename, fname))
-        pagename = self._replace(('PAGE', pagename))
-        if from_this_page:
-            name = fname
+    def _macro_repl(self, word):
+        # we use [[...]] for links now, macros will be <<...>>
+        stripped_old = word[2:-2]
+        decorated_new = "<<%s>>" % stripped_old
+        # XXX later check whether some to be renamed pagename is used as macro param
+        return decorated_new
+
+    def _word_repl(self, word, text=None):
+        """Handle WikiNames."""
+        if not text:
+            return word
+        else: # internal use:
+            return '[[%s|%s]]' % (word, text)
+
+    def _wikiname_bracket_repl(self, word):
+        """Handle special-char wikinames."""
+        pagename = word[2:-2]
+        if pagename:
+            pagename = self._replace(('PAGE', pagename))
+            return '[[%s]]' % pagename
         else:
-            name = "%s/%s" % (pagename, fname)
-        name = self._intelli_quote(name)
-        if text:
-            text = ' ' + text
-        return "%s:%s%s" % (scheme, name, text)
+            return word
 
     def _interwiki_repl(self, word):
         """Handle InterWiki links."""
@@ -173,106 +157,179 @@
         if wikitag_bad:
             return word
         else:
-            scheme, wikiname, pagename, text = self.interwiki("wiki:" + word)
-            if wikiname == 'Self':
-                return '["%s"]' % pagename # optimize special case
+            wikiname, pagename = word.split(':', 1)
+            pagename = wikiutil.url_unquote(pagename) # maybe someone has used %20 for blanks in pagename
+            camelcase = wikiutil.isStrictWikiname(pagename)
+            if wikiname in ('Self', self.request.cfg.interwikiname):
+                pagename = self._replace(('PAGE', pagename))
+                if camelcase:
+                    return '%s' % pagename # optimize special case
+                else:
+                    return '[[%s]]' % pagename # optimize special case
             else:
-                pagename = self._intelli_quote(pagename)
-                return "%s:%s" % (wikiname, pagename)
+                if ' ' in pagename: # we could get a ' '  by urlunquoting
+                    return '[[%s:%s]]' % (wikiname, pagename)
+                else:
+                    return '%s:%s' % (wikiname, pagename)
+
+    def interwiki(self, url_and_text):
+        if len(url_and_text) == 1:
+            url = url_and_text[0]
+            text = ''
+        else:
+            url, text = url_and_text
+            text = '|' + text
+
+        # keep track of whether this is a self-reference, so links
+        # are always shown even the page doesn't exist.
+        scheme, url = url.split(':', 1)
+        wikiname, pagename = wikiutil.split_wiki(url)
+        if (url.startswith(wikiutil.CHILD_PREFIX) or # fancy link to subpage [wiki:/SubPage text]
+            Page(self.request, url).exists()): # fancy link to local page [wiki:LocalPage text]
+            pagename = wikiutil.url_unquote(url)
+            pagename = self._replace_target(pagename)
+            return '[[%s%s]]' % (pagename, text)
+        if wikiname in ('Self', self.request.cfg.interwikiname, ''): # [wiki:Self:LocalPage text] or [:LocalPage:text]
+            pagename = wikiutil.url_unquote(pagename)
+            pagename = self._replace_target(pagename)
+            return '[[%s%s]]' % (pagename, text)
+
+        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, url)
+        wikitail = wikiutil.url_unquote(wikitail)
+
+        # link to self?
+        if wikitag is None:
+            if wikiutil.isPicture(wikitail):
+                return '{{%s%s}}' % (wikitail, text)
+            else:
+                return '[[%s%s]]' % (wikitail, text)
+        else:
+            if wikiutil.isPicture(wikitail):
+                return '{{%s:%s%s}}' % (wikitag, wikitail, text)
+            else:
+                return '[[%s:%s%s]]' % (wikitag, wikitail, text)
+
+    def attachment(self, url_and_text):
+        """ This gets called on attachment URLs. """
+        if len(url_and_text) == 1:
+            url = url_and_text[0]
+            text = ''
+        else:
+            url, text = url_and_text
+            text = '|' + text
+
+        scheme, fname = url.split(":", 1)
+        #scheme, fname, text = wikiutil.split_wiki(target_and_text)
+
+        pagename, fname = AttachFile.absoluteName(fname, self.pagename)
+        from_this_page = pagename == self.pagename
+        fname = self._replace(('FILE', pagename, fname))
+        fname = wikiutil.url_unquote(fname, want_unicode=True)
+        fname = self._replace(('FILE', pagename, fname))
+        pagename = self._replace(('PAGE', pagename))
+        if from_this_page:
+            name = fname
+        else:
+            name = "%s/%s" % (pagename, fname)
+
+        if scheme == 'drawing':
+            return "{{drawing:%s%s}}" % (name, text)
+
+        # check for image URL, and possibly return IMG tag
+        # (images are always inlined, just like for other URLs)
+        if wikiutil.isPicture(name):
+            return "{{attachment:%s%s}}" % (name, text)
+
+        # inline the attachment
+        if scheme == 'inline':
+            return '{{attachment:%s%s}}' % (name, text)
+        else: # 'attachment'
+            return '[[attachment:%s%s]]' % (name, text)
 
     def _url_repl(self, word):
         """Handle literal URLs including inline images."""
         scheme = word.split(":", 1)[0]
 
-        if scheme == "wiki":
-            scheme, wikiname, pagename, text = self.interwiki(word)
-            if wikiname == 'Self':
-                return '["%s"]' % pagename # optimize special case
-            else:
-                pagename = self._intelli_quote(pagename)
-                return "%s:%s:%s" % (scheme, wikiname, pagename)
-
+        if scheme == 'wiki':
+            return self.interwiki([word])
         if scheme in self.attachment_schemas:
-            return self.attachment(word)
-
-        if wikiutil.isPicture(word):
-            # Get image name http://here.com/dir/image.gif -> image
-            name = word.split('/')[-1]
-            name = ''.join(name.split('.')[:-1])
-            return word # self.formatter.image(src=word, alt=name)
-        else:
-            return word # word, scheme
+            return '%s' % self.attachment([word])
 
-    def _wikiname_bracket_repl(self, text):
-        """Handle special-char wikinames with link text, like:
-           ["Jim O'Brian" Jim's home page] or ['Hello "world"!' a page with doublequotes]i
-        """
-        word = text[1:-1] # strip brackets
-        first_char = word[0]
-        if first_char in wikiutil.QUOTE_CHARS:
-            # split on closing quote
-            target, linktext = word[1:].split(first_char, 1)
-            target = self._replace_target(target)
-            target = wikiutil.quoteName(target)
-        else: # not quoted
-            # split on whitespace
-            target, linktext = word.split(None, 1)
-            target = self._replace_target(target)
-            target = self._intelli_quote(target)
-        linktext = linktext.strip()
-        if linktext:
-            linktext = ' ' + linktext
-        return '[%s%s]' % (target, linktext)
-
+        if wikiutil.isPicture(word): # magic will go away in 1.6!
+            return '{{%s}}' % word # new markup for inline images
+        else:
+            return word
 
     def _url_bracket_repl(self, word):
         """Handle bracketed URLs."""
         word = word[1:-1] # strip brackets
 
-        # Local extended link? [:page name:link text]
+        # Local extended link?
         if word[0] == ':':
             words = word[1:].split(':', 1)
             link, text = (words + ['', ''])[:2]
             if link.strip() == text.strip():
                 text = ''
             link = self._replace_target(link)
-            link = wikiutil.quoteName(link)
             if text:
-                text = ' ' + text
-            return '[%s%s]' % (link, text) # use freelink with text
+                text = '|' + text
+            return '[[%s%s]]' % (link, text)
 
-        scheme_and_rest = word.split(":", 1)
-        if len(scheme_and_rest) == 2: # scheme given
-            scheme, rest = scheme_and_rest
-            if scheme == "wiki":
-                scheme, wikiname, pagename, text = self.interwiki(word, pretty_url=1)
-                if wikiname == 'Self':
-                    if text:
-                        text = ' %s' % text
-                    return '["%s"%s]' % (pagename, text)
-                else:
-                    pagename = self._intelli_quote(pagename)
-                    if text:
-                        text = ' %s' % text
-                    return "[%s:%s:%s%s]" % (scheme, wikiname, pagename, text)
-            if scheme in self.attachment_schemas:
-                return '[%s]' % self.attachment(word, pretty_url=1)
+        # Traditional split on space
+        words = word.split(None, 1)
+        if words[0][0] == '#':
+            # anchor link
+            link, text = (words + ['', ''])[:2]
+            if link.strip() == text.strip():
+                text = ''
+            #link = self._replace_target(link)
+            if text:
+                text = '|' + text
+            return '[[%s%s]]' % (link, text)
 
-        words = word.split(None, 1)
-        if len(words) == 1:
-            link, text = words[0], ''
+        scheme = words[0].split(":", 1)[0]
+        if scheme == "wiki":
+            return self.interwiki(words)
+            #scheme, wikiname, pagename, text = self.interwiki(word)
+            #print "%r %r %r %r" % (scheme, wikiname, pagename, text)
+            #if wikiname in ('Self', self.request.cfg.interwikiname, ''):
+            #    if text:
+            #        text = '|' + text
+            #    return '[[%s%s]]' % (pagename, text)
+            #else:
+            #    if text:
+            #        text = '|' + text
+            #    return "[[%s:%s%s]]" % (wikiname, pagename, text)
+        if scheme in self.attachment_schemas:
+            m = self.attachment(words)
+            if m.startswith('{{') and m.endswith('}}'):
+                # with url_bracket markup, 1.5.8 parser does not embed, but link!
+                m = '[[%s]]' % m[2:-2]
+            return m
+
+        target, desc = (words + ['', ''])[:2]
+        if wikiutil.isPicture(desc) and re.match(self.url_rule, desc):
+            #return '[[%s|{{%s|%s}}]]' % (words[0], words[1], words[0])
+            return '[[%s|{{%s}}]]' % (target, desc)
         else:
-            link, text = words
-        if text:
-            text = ' ' + text
-        return '[%s%s]' % (link, text)
+            if desc:
+                desc = '|' + desc
+            return '[[%s%s]]' % (target, desc)
 
-    # SCANNING ---------------------------------------------------------------
+    def _pre_repl(self, word):
+        w = word.strip()
+        if w == '{{{' and not self.in_pre:
+            self.in_pre = True
+        elif w == '}}}' and self.in_pre:
+            self.in_pre = False
+        return word
+
+    def _processor_repl(self, word):
+        self.in_pre = True
+        return word
+
     def scan(self, scan_re, line):
-        """ Scans one line
-
-        Append text before match, invoke replace() with match, and add text after match.
-        """
+        """ Scans one line - append text before match, invoke replace() with match, and add text after match.  """
         result = []
         lastpos = 0
 
@@ -288,6 +345,7 @@
         result.append(line[lastpos:])
         return u''.join(result)
 
+
     def replace(self, match):
         """ Replace match using type name """
         result = []
@@ -295,6 +353,7 @@
             if hit is not None and not _type in ["hmarker", ]:
                 # Get replace method and replace hit
                 replace = getattr(self, '_' + _type + '_repl')
+                # print _type, hit
                 result.append(replace(hit))
                 return ''.join(result)
         else:
@@ -315,21 +374,21 @@
         self.request = request
         # prepare regex patterns
         rules = self.formatting_rules.replace('\n', '|')
-        if 1: # self.cfg.bang_meta:
+        if self.request.cfg.bang_meta:
             rules = ur'(?P<notword>!%(word_rule)s)|%(rules)s' % {
                 'word_rule': self.word_rule,
                 'rules': rules,
             }
-        pre_rules = self.pre_formatting_rules.replace('\n', '|')
+        #pre_rules = self.pre_formatting_rules.replace('\n', '|')
+        #pre_scan_re = re.compile(pre_rules, re.UNICODE)
         scan_re = re.compile(rules, re.UNICODE)
-        pre_scan_re = re.compile(pre_rules, re.UNICODE)
         eol_re = re.compile(r'\r?\n', re.UNICODE)
 
         rawtext = self.raw
 
         # remove last item because it's guaranteed to be empty
         self.lines = eol_re.split(rawtext)[:-1]
-        self.in_processing_instructions = 1
+        self.in_processing_instructions = True
 
         # Main loop
         for line in self.lines:
@@ -343,38 +402,14 @@
                         found = True
                         break
                 if not found:
-                    self.in_processing_instructions = 0
+                    self.in_processing_instructions = False
                 else:
                     continue # do not parse this line
-            if self.in_pre:
-                # still looking for processing instructions
-                if self.in_pre == 'search_parser':
-                    if line.strip().startswith("#!"):
-                        self.in_pre = True
-                        self.request.write(line + '\r\n')
-                        continue
-                    else:
-                        self.in_pre = True
+            if not line.strip():
+                self.request.write(line + '\r\n')
             else:
-                # Paragraph break on empty lines
-                if not line.strip():
-                    self.request.write(line + '\r\n')
-                    continue
+                # Scan line, format and write
+                scanning_re = self.in_pre and pre_scan_re or scan_re
+                formatted_line = self.scan(scanning_re, line)
+                self.request.write(formatted_line + '\r\n')
 
-            # Scan line, format and write
-            scanning_re = self.in_pre and pre_scan_re or scan_re
-            formatted_line = self.scan(scanning_re, line)
-            self.request.write(formatted_line + '\r\n')
-
-def convert_wiki(request, pagename, intext, renames):
-    """ Convert content written in wiki markup """
-    noeol = False
-    if not intext.endswith('\r\n'):
-        intext += '\r\n'
-        noeol = True
-    p = Converter(pagename, intext, renames)
-    res = request.redirectedOutput(p.convert, request)
-    if noeol:
-        res = res[:-2]
-    return res
-
--- a/MoinMoin/script/migration/_tests/test_conv160_wiki.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/script/migration/_tests/test_conv160_wiki.py	Tue Aug 21 15:47:56 2007 +0200
@@ -18,11 +18,13 @@
     @copyright: 2007 MoinMoin:ThomasWaldmann
     @license: GNU GPL, see COPYING for details.
 """
+import py
+#py.test.skip("broken")
 
 from MoinMoin.script.migration._conv160_wiki import convert_wiki
 
 class TestWikiConversion:
-    """ test the wiki markup conversion for 1.6.0 """
+    """ test the wiki markup conversion 1.5.8 -> 1.6.0 """
     def test_absolute(self):
         request = self.request
         pagename = 'TestPage'
@@ -36,66 +38,80 @@
 
         tests = [
             # FAILING tests:
-            #('[wiki:/OtherPage]', rename_some_page, '[wiki:/OtherPage]'),
-            #('[wiki:/OtherPage other page]', rename_some_page, '[wiki:/OtherPage other page]'),
-            #('[attachment:My%20Attachment.jpg:it works]', {}, '[attachment:"My Attachment.jpg" it works]'),
-            #('[wiki:LinuxWiki: LinuxWiki.de]', {}, '[wiki:LinuxWiki: LinuxWiki.de]'),
+
+            # does not work in 1.5.8, no need to convert:
             #('[:MeatBall:CleanLinking meatball-wiki: clean linking]', {}, '[:MeatBall:CleanLinking meatball-wiki: clean linking]'),
 
-            # ambiguity!!! can be resolved with some interwiki map lookup
-            # and transformed to wiki:SeaPig:BrianDorsey if SeaPig is in
-            # interwiki map, but no page SeaPig exists.
-            #('[wiki:MacroMarket/EmbedObject EO]', {}, '["MacroMarket/EmbedObject" EO]'),
-            ('[wiki:SeaPig/BrianDorsey]', {}, '[wiki:SeaPig:BrianDorsey]'),
+            # does not work in 1.5.8, no need to convert:
+            #('[attachment:some_page.txt attachment:some_page.png]', rename_some_page, '[[attachment:some_page.txt|{{attachment:some_page.png}}]]'),
 
-            # "nothing changed" checks
+            # "nothing changed" checks (except markup)
             ('', {}, ''),
             ('CamelCase', {}, 'CamelCase'),
             ('MoinMaster:CamelCase', {}, 'MoinMaster:CamelCase'),
+            ('[wiki:LinuxWiki: LinuxWiki.de]', {}, '[[LinuxWiki:|LinuxWiki.de]]'),
+            # does not work in 1.5.8, no need to convert:
+            #('[wiki:MacroMarket/EmbedObject EO]', {}, '["MacroMarket/EmbedObject" EO]'),
+            ('[wiki:MoinMoin/FrontPage]', {}, '[[MoinMoin:FrontPage]]'),
+            ('[wiki:/OtherPage]', rename_some_page, '[[/OtherPage]]'),
+            ('[wiki:/OtherPage other page]', rename_some_page, '[[/OtherPage|other page]]'),
             ('some_text', {}, 'some_text'),
-            ('["some_text"]', {}, '["some_text"]'),
+            ('["some_text"]', {}, '[[some_text]]'),
             ('some_page', rename_some_page, 'some_page'), # not a link
             ('{{{["some_page"]}}}', rename_some_page, '{{{["some_page"]}}}'), # not a link
             ('`["some_page"]`', rename_some_page, '`["some_page"]`'), # not a link
-            ('["OtherPage/some_page"]', rename_some_page, '["OtherPage/some_page"]'), # different link
+            ('["OtherPage/some_page"]', rename_some_page, '[[OtherPage/some_page]]'), # different link
             ('MoinMaster:some_page', rename_some_page, 'MoinMaster:some_page'), # external link
             ('http://some_server/some_page', rename_some_page, 'http://some_server/some_page'), # external link
-            ('[http://some_server/some_page]', rename_some_page, '[http://some_server/some_page]'), # external link
-            ('[#some_page]', rename_some_page, '[#some_page]'), # link to anchor that has same name
-            ('[attachment:some_page.png]', rename_some_page, '[attachment:some_page.png]'), # att, not page
-            ('[attachment:some_page.png test picture]', rename_some_page, '[attachment:some_page.png test picture]'), # att, not page
-            ('[attachment:some_page.txt attachment:some_page.png]', rename_some_page, '[attachment:some_page.txt attachment:some_page.png]'),
+            ('[http://some_server/some_page]', rename_some_page, '[[http://some_server/some_page]]'), # external link
+            ('[#some_page]', rename_some_page, '[[#some_page]]'), # link to anchor that has same name
+            ('[attachment:some_page.png]', rename_some_page, '[[attachment:some_page.png]]'), # att, not page
+            ('[attachment:some_page.png test picture]', rename_some_page, '[[attachment:some_page.png|test picture]]'), # att, not page
+            # url unquote stuff (%20 was popular for space)
+            ('attachment:My%20Attachment.jpg', {}, '{{attachment:My Attachment.jpg}}'), # embed!
+            ('[attachment:My%20Attachment.jpg]', {}, '[[attachment:My Attachment.jpg]]'), # link!
+            ('[attachment:My%20Attachment.jpg it works]', {}, '[[attachment:My Attachment.jpg|it works]]'),
 
             # page rename changes result
-            ('["some_page"]', rename_some_page, '["some page"]'),
-            ('[:some_page]', rename_some_page, '["some page"]'),
-            ('[:some_page:]', rename_some_page, '["some page"]'),
-            ('[:some_page:some text]', rename_some_page, '["some page" some text]'),
-            ('Self:some_page', rename_some_page, '["some page"]'),
-            ('wiki:Self:some_page', rename_some_page, '["some page"]'),
-            ('[wiki:Self:some_page some text]', rename_some_page, '["some page" some text]'),
-            # XXX FAILS ('wiki:Self:some_page#some_anchor', rename_some_page, '["some page"#some_anchor]'),
+            ('["some_page"]', rename_some_page, '[[some page]]'),
+            ('[:some_page]', rename_some_page, '[[some page]]'),
+            ('[:some_page:]', rename_some_page, '[[some page]]'),
+            ('[:some_page:some text]', rename_some_page, '[[some page|some text]]'),
+            ('Self:some_page', rename_some_page, '[[some page]]'),
+            ('wiki:Self:some_page', rename_some_page, '[[some page]]'),
+            ('[wiki:Self:some_page some text]', rename_some_page, '[[some page|some text]]'),
+            ('wiki:Self:some_page#some_anchor', rename_some_page, '[[some page#some_anchor]]'),
 
             # other markup changes we do
-            ('[:other page]', {}, '["other page"]'),
-            ('[:other page:]', {}, '["other page"]'),
-            ('[:other page:other text]', {}, '["other page" other text]'),
-            # FAILS ('Self:CamelCase', {}, 'CamelCase'),
-            ('[wiki:WikiPedia:Lynx_%28web_browser%29 Lynx]', {}, '[wiki:WikiPedia:"Lynx_(web_browser)" Lynx]'),
-            ('[:Something:Something]', {}, '["Something"]'), # optimize markup
+            ('[:other page]', {}, '[[other page]]'),
+            ('[:other page:]', {}, '[[other page]]'),
+            ('[:other page:other text]', {}, '[[other page|other text]]'),
+            ('Self:CamelCase', {}, 'CamelCase'),
+            ('[wiki:WikiPedia:Lynx_%28web_browser%29 Lynx]', {}, '[[WikiPedia:Lynx_(web_browser)|Lynx]]'),
+            ('[:Something:Something]', {}, '[[Something]]'), # optimize markup
 
             # "nothing changed" checks
-            ('attachment:OtherPage/with_underscore', rename_some_file, 'attachment:OtherPage/with_underscore'),
+            ('attachment:OtherPage/with_underscore', rename_some_file, '[[attachment:OtherPage/with_underscore]]'),
 
             # file rename changes result
-            ('attachment:with_underscore', rename_some_file, 'attachment:"without underscore"'),
-            ('attachment:TestPage/with_underscore', rename_some_file, 'attachment:"without underscore"'), # remove superfluous pagename
+            ('attachment:with_underscore', rename_some_file, '[[attachment:without underscore]]'),
+            ('attachment:TestPage/with_underscore', rename_some_file, '[[attachment:without underscore]]'), # remove superfluous pagename
 
             # attachment syntax: kill %20
-            ('attachment:with%20blank', rename_some_file, 'attachment:without_blank'), # plus rename
-            ('attachment:keep%20blank', rename_some_file, 'attachment:"keep blank"'), # no rename
-            ('attachment:TestPage/keep%20blank', rename_some_file, 'attachment:"keep blank"'), # remove superfluous pagename
-            ('attachment:OtherPage/keep%20blank', rename_some_file, 'attachment:"OtherPage/keep blank"'),
+            ('attachment:with%20blank', rename_some_file, '[[attachment:without_blank]]'), # plus rename
+            ('attachment:keep%20blank', rename_some_file, '[[attachment:keep blank]]'), # no rename
+            ('attachment:TestPage/keep%20blank', rename_some_file, '[[attachment:keep blank]]'), # remove superfluous pagename
+            ('attachment:OtherPage/keep%20blank', rename_some_file, '[[attachment:OtherPage/keep blank]]'),
+
+            # embed images
+            ('http://server/image.png', {}, '{{http://server/image.png}}'),
+            ('attachment:image.gif', {}, '{{attachment:image.gif}}'),
+            ('inline:image.jpg', {}, '{{attachment:image.jpg}}'), # inline is now implied by {{...}}
+            ('drawing:image', {}, '{{drawing:image}}'),
+
+            # macros
+            ('[[BR]]', {}, '<<BR>>'),
+
         ]
         for data, renames, expected in tests:
             assert convert_wiki(request, pagename, data, renames) == expected
@@ -109,7 +125,7 @@
         }
         tests = [
             # "nothing changed" checks
-            ('["../sister_norename"]', rename_some_page, '["../sister_norename"]'),
+            ('["../sister_norename"]', rename_some_page, '[[../sister_norename]]'),
 
             # renames
             # FAILS, see TODO in _replace:
@@ -126,7 +142,7 @@
         }
         tests = [
             # "nothing changed" checks
-            ('["/subpage_norename"]', rename_some_page, '["/subpage_norename"]'),
+            ('["/subpage_norename"]', rename_some_page, '[[/subpage_norename]]'),
 
             # renames
             # FAILS, see TODO in _replace:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/script/migration/text_moin158_wiki.py	Tue Aug 21 15:47:56 2007 +0200
@@ -0,0 +1,1137 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - MoinMoin Wiki Markup Parser
+
+    @copyright: 2000, 2001, 2002 by Jürgen Hermann <jh@web.de>
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import os, re
+from MoinMoin import config, wikiutil
+from MoinMoin import macro as wikimacro
+from MoinMoin.Page import Page
+from MoinMoin.util import web
+
+Dependencies = []
+
+class Parser:
+    """
+        Object that turns Wiki markup into HTML.
+
+        All formatting commands can be parsed one line at a time, though
+        some state is carried over between lines.
+
+        Methods named like _*_repl() are responsible to handle the named regex
+        patterns defined in print_html().
+    """
+
+    # allow caching
+    caching = 1
+    Dependencies = []
+
+    # some common strings
+    PARENT_PREFIX = wikiutil.PARENT_PREFIX
+    punct_pattern = re.escape(u'''"\'}]|:,.)?!''')
+    attachment_schemas = ["attachment", "inline", "drawing", ]
+    url_schemas = ['http', 'https', 'ftp', 'wiki', 'mailto', 'nntp', 'news',
+                   'telnet', 'file', 'irc', 'ircs',
+                   'webcal', 'ed2k', 'xmpp', 'rootz',
+                  ]
+    url_pattern = u'|'.join(url_schemas + attachment_schemas)
+
+    # some common rules
+    word_rule = ur'(?:(?<![%(u)s%(l)s])|^)%(parent)s(?:%(subpages)s(?:[%(u)s][%(l)s]+){2,})+(?![%(u)s%(l)s]+)' % {
+        'u': config.chars_upper,
+        'l': config.chars_lower,
+        'subpages': wikiutil.CHILD_PREFIX + '?',
+        'parent': ur'(?:%s)?' % re.escape(PARENT_PREFIX),
+    }
+    url_rule = ur'%(url_guard)s(%(url)s)\:([^\s\<%(punct)s]|([%(punct)s][^\s\<%(punct)s]))+' % {
+        'url_guard': u'(^|(?<!\w))',
+        'url': url_pattern,
+        'punct': punct_pattern,
+    }
+
+    ol_rule = ur"^\s+(?:[0-9]+|[aAiI])\.(?:#\d+)?\s"
+    dl_rule = ur"^\s+.*?::\s"
+
+    config_smileys = dict([(key, None) for key in config.smileys])
+
+    # the big, fat, ugly one ;)
+    formatting_rules = ur"""(?P<ent_numeric>&#(\d{1,5}|x[0-9a-fA-F]+);)
+(?:(?P<emph_ibb>'''''(?=[^']+'''))
+(?P<emph_ibi>'''''(?=[^']+''))
+(?P<emph_ib_or_bi>'{5}(?=[^']))
+(?P<emph>'{2,3})
+(?P<u>__)
+(?P<sup>\^.*?\^)
+(?P<sub>,,[^,]{1,40},,)
+(?P<tt>\{\{\{.*?\}\}\})
+(?P<processor>(\{\{\{(#!.*|\s*$)))
+(?P<pre>(\{\{\{ ?|\}\}\}))
+(?P<small>(\~- ?|-\~))
+(?P<big>(\~\+ ?|\+\~))
+(?P<strike>(--\(|\)--))
+(?P<rule>-{4,})
+(?P<comment>^\#\#.*$)
+(?P<macro>\[\[(%%(macronames)s)(?:\(.*?\))?\]\]))
+(?P<ol>%(ol_rule)s)
+(?P<dl>%(dl_rule)s)
+(?P<li>^\s+\*\s*)
+(?P<li_none>^\s+\.\s*)
+(?P<indent>^\s+)
+(?P<tableZ>\|\| $)
+(?P<table>(?:\|\|)+(?:<[^>]*?>)?(?!\|? $))
+(?P<heading>^\s*(?P<hmarker>=+)\s.*\s(?P=hmarker) $)
+(?P<interwiki>[A-Z][a-zA-Z]+\:[^\s'\"\:\<\|]([^\s%(punct)s]|([%(punct)s][^\s%(punct)s]))+)
+(?P<word>%(word_rule)s)
+(?P<url_bracket>\[((%(url)s)\:|#|\:)[^\s\]]+(\s[^\]]+)?\])
+(?P<url>%(url_rule)s)
+(?P<email>[-\w._+]+\@[\w-]+(\.[\w-]+)+)
+(?P<smiley>(?<=\s)(%(smiley)s)(?=\s))
+(?P<smileyA>^(%(smiley)s)(?=\s))
+(?P<ent_symbolic>&\w+;)
+(?P<ent>[<>&])
+(?P<wikiname_bracket>\[".*?"\])
+(?P<tt_bt>`.*?`)"""  % {
+
+        'url': url_pattern,
+        'punct': punct_pattern,
+        'ol_rule': ol_rule,
+        'dl_rule': dl_rule,
+        'url_rule': url_rule,
+        'word_rule': word_rule,
+        'smiley': u'|'.join(map(re.escape, config_smileys.keys()))}
+
+    # Don't start p before these
+    no_new_p_before = ("heading rule table tableZ tr td "
+                       "ul ol dl dt dd li li_none indent "
+                       "macro processor pre")
+    no_new_p_before = no_new_p_before.split()
+    no_new_p_before = dict(zip(no_new_p_before, [1] * len(no_new_p_before)))
+
+    def __init__(self, raw, request, **kw):
+        self.raw = raw
+        self.request = request
+        self.form = request.form
+        self._ = request.getText
+        self.cfg = request.cfg
+        self.line_anchors = kw.get('line_anchors', True)
+        self.macro = None
+        self.start_line = kw.get('start_line', 0)
+
+        self.is_em = 0
+        self.is_b = 0
+        self.is_u = 0
+        self.is_strike = 0
+        self.lineno = 0
+        self.in_list = 0 # between <ul/ol/dl> and </ul/ol/dl>
+        self.in_li = 0 # between <li> and </li>
+        self.in_dd = 0 # between <dd> and </dd>
+        self.in_pre = 0
+        self.in_table = 0
+        self.is_big = False
+        self.is_small = False
+        self.inhibit_p = 0 # if set, do not auto-create a <p>aragraph
+        self.titles = request._page_headings
+
+        # holds the nesting level (in chars) of open lists
+        self.list_indents = []
+        self.list_types = []
+
+        self.formatting_rules = self.formatting_rules % {'macronames': u'|'.join(wikimacro.getNames(self.cfg))}
+
+    def _close_item(self, result):
+        #result.append("<!-- close item begin -->\n")
+        if self.in_table:
+            result.append(self.formatter.table(0))
+            self.in_table = 0
+        if self.in_li:
+            self.in_li = 0
+            if self.formatter.in_p:
+                result.append(self.formatter.paragraph(0))
+            result.append(self.formatter.listitem(0))
+        if self.in_dd:
+            self.in_dd = 0
+            if self.formatter.in_p:
+                result.append(self.formatter.paragraph(0))
+            result.append(self.formatter.definition_desc(0))
+        #result.append("<!-- close item end -->\n")
+
+
+    def interwiki(self, url_and_text, **kw):
+        # TODO: maybe support [wiki:Page http://wherever/image.png] ?
+        if len(url_and_text) == 1:
+            url = url_and_text[0]
+            text = None
+        else:
+            url, text = url_and_text
+
+        # keep track of whether this is a self-reference, so links
+        # are always shown even the page doesn't exist.
+        is_self_reference = 0
+        url2 = url.lower()
+        if url2.startswith('wiki:self:'):
+            url = url[10:] # remove "wiki:self:"
+            is_self_reference = 1
+        elif url2.startswith('wiki:'):
+            url = url[5:] # remove "wiki:
+
+        tag, tail = wikiutil.split_wiki(url)
+        if text is None:
+            if tag:
+                text = tail
+            else:
+                text = url
+                url = ""
+        elif (url.startswith(wikiutil.CHILD_PREFIX) or # fancy link to subpage [wiki:/SubPage text]
+              is_self_reference or # [wiki:Self:LocalPage text] or [:LocalPage:text]
+              Page(self.request, url).exists()): # fancy link to local page [wiki:LocalPage text]
+            return self._word_repl(url, text)
+
+        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, url)
+        href = wikiutil.join_wiki(wikiurl, wikitail)
+
+        # check for image URL, and possibly return IMG tag
+        if not kw.get('pretty_url', 0) and wikiutil.isPicture(wikitail):
+            return self.formatter.image(src=href)
+
+        # link to self?
+        if wikitag is None:
+            return self._word_repl(wikitail)
+
+        return (self.formatter.interwikilink(1, tag, tail) +
+                self.formatter.text(text) +
+                self.formatter.interwikilink(0, tag, tail))
+
+    def attachment(self, url_and_text, **kw):
+        """ This gets called on attachment URLs.
+        """
+        _ = self._
+        if len(url_and_text) == 1:
+            url = url_and_text[0]
+            text = None
+        else:
+            url, text = url_and_text
+
+        inline = url[0] == 'i'
+        drawing = url[0] == 'd'
+        url = url.split(":", 1)[1]
+        url = wikiutil.url_unquote(url, want_unicode=True)
+        text = text or url
+
+        from MoinMoin.action import AttachFile
+        if drawing:
+            return self.formatter.attachment_drawing(url, text)
+
+        # check for image URL, and possibly return IMG tag
+        # (images are always inlined, just like for other URLs)
+        if not kw.get('pretty_url', 0) and wikiutil.isPicture(url):
+            return self.formatter.attachment_image(url)
+
+        # inline the attachment
+        if inline:
+            return self.formatter.attachment_inlined(url, text)
+
+        return self.formatter.attachment_link(url, text)
+
+    def _u_repl(self, word):
+        """Handle underline."""
+        self.is_u = not self.is_u
+        return self.formatter.underline(self.is_u)
+
+    def _strike_repl(self, word):
+        """Handle strikethrough."""
+        # XXX we don't really enforce the correct sequence --( ... )-- here
+        self.is_strike = not self.is_strike
+        return self.formatter.strike(self.is_strike)
+
+    def _small_repl(self, word):
+        """Handle small."""
+        if word.strip() == '~-' and self.is_small:
+            return self.formatter.text(word)
+        if word.strip() == '-~' and not self.is_small:
+            return self.formatter.text(word)
+        self.is_small = not self.is_small
+        return self.formatter.small(self.is_small)
+
+    def _big_repl(self, word):
+        """Handle big."""
+        if word.strip() == '~+' and self.is_big:
+            return self.formatter.text(word)
+        if word.strip() == '+~' and not self.is_big:
+            return self.formatter.text(word)
+        self.is_big = not self.is_big
+        return self.formatter.big(self.is_big)
+
+    def _emph_repl(self, word):
+        """Handle emphasis, i.e. '' and '''."""
+        ##print "#", self.is_b, self.is_em, "#"
+        if len(word) == 3:
+            self.is_b = not self.is_b
+            if self.is_em and self.is_b:
+                self.is_b = 2
+            return self.formatter.strong(self.is_b)
+        else:
+            self.is_em = not self.is_em
+            if self.is_em and self.is_b:
+                self.is_em = 2
+            return self.formatter.emphasis(self.is_em)
+
+    def _emph_ibb_repl(self, word):
+        """Handle mixed emphasis, i.e. ''''' followed by '''."""
+        self.is_b = not self.is_b
+        self.is_em = not self.is_em
+        if self.is_em and self.is_b:
+            self.is_b = 2
+        return self.formatter.emphasis(self.is_em) + self.formatter.strong(self.is_b)
+
+    def _emph_ibi_repl(self, word):
+        """Handle mixed emphasis, i.e. ''''' followed by ''."""
+        self.is_b = not self.is_b
+        self.is_em = not self.is_em
+        if self.is_em and self.is_b:
+            self.is_em = 2
+        return self.formatter.strong(self.is_b) + self.formatter.emphasis(self.is_em)
+
+    def _emph_ib_or_bi_repl(self, word):
+        """Handle mixed emphasis, exactly five '''''."""
+        ##print "*", self.is_b, self.is_em, "*"
+        b_before_em = self.is_b > self.is_em > 0
+        self.is_b = not self.is_b
+        self.is_em = not self.is_em
+        if b_before_em:
+            return self.formatter.strong(self.is_b) + self.formatter.emphasis(self.is_em)
+        else:
+            return self.formatter.emphasis(self.is_em) + self.formatter.strong(self.is_b)
+
+
+    def _sup_repl(self, word):
+        """Handle superscript."""
+        return self.formatter.sup(1) + \
+            self.formatter.text(word[1:-1]) + \
+            self.formatter.sup(0)
+
+    def _sub_repl(self, word):
+        """Handle subscript."""
+        return self.formatter.sub(1) + \
+            self.formatter.text(word[2:-2]) + \
+            self.formatter.sub(0)
+
+
+    def _rule_repl(self, word):
+        """Handle sequences of dashes."""
+        result = self._undent() + self._closeP()
+        if len(word) <= 4:
+            result = result + self.formatter.rule()
+        else:
+            # Create variable rule size 1 - 6. Actual size defined in css.
+            size = min(len(word), 10) - 4
+            result = result + self.formatter.rule(size)
+        return result
+
+
+    def _word_repl(self, word, text=None):
+        """Handle WikiNames."""
+
+        # check for parent links
+        # !!! should use wikiutil.AbsPageName here, but setting `text`
+        # correctly prevents us from doing this for now
+        if word.startswith(wikiutil.PARENT_PREFIX):
+            if not text:
+                text = word
+            word = '/'.join(filter(None, self.formatter.page.page_name.split('/')[:-1] + [word[wikiutil.PARENT_PREFIX_LEN:]]))
+
+        if not text:
+            # if a simple, self-referencing link, emit it as plain text
+            if word == self.formatter.page.page_name:
+                return self.formatter.text(word)
+            text = word
+        if word.startswith(wikiutil.CHILD_PREFIX):
+            word = self.formatter.page.page_name + '/' + word[wikiutil.CHILD_PREFIX_LEN:]
+
+        # handle anchors
+        parts = word.split("#", 1)
+        anchor = ""
+        if len(parts) == 2:
+            word, anchor = parts
+
+        return (self.formatter.pagelink(1, word, anchor=anchor) +
+                self.formatter.text(text) +
+                self.formatter.pagelink(0, word))
+
+    def _notword_repl(self, word):
+        """Handle !NotWikiNames."""
+        return self.formatter.nowikiword(word[1:])
+
+    def _interwiki_repl(self, word):
+        """Handle InterWiki links."""
+        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, word)
+        if wikitag_bad:
+            return self.formatter.text(word)
+        else:
+            return self.interwiki(["wiki:" + word])
+
+
+    def _url_repl(self, word):
+        """Handle literal URLs including inline images."""
+        scheme = word.split(":", 1)[0]
+
+        if scheme == "wiki":
+            return self.interwiki([word])
+        if scheme in self.attachment_schemas:
+            return self.attachment([word])
+
+        if wikiutil.isPicture(word):
+            word = wikiutil.mapURL(self.request, word)
+            # Get image name http://here.com/dir/image.gif -> image
+            name = word.split('/')[-1]
+            name = ''.join(name.split('.')[:-1])
+            return self.formatter.image(src=word, alt=name)
+        else:
+            return (self.formatter.url(1, word, css=scheme) +
+                    self.formatter.text(word) +
+                    self.formatter.url(0))
+
+
+    def _wikiname_bracket_repl(self, word):
+        """Handle special-char wikinames."""
+        wikiname = word[2:-2]
+        if wikiname:
+            return self._word_repl(wikiname)
+        else:
+            return self.formatter.text(word)
+
+
+    def _url_bracket_repl(self, word):
+        """Handle bracketed URLs."""
+
+        # Local extended link?
+        if word[1] == ':':
+            words = word[2:-1].split(':', 1)
+            if len(words) == 1:
+                words = words * 2
+            words[0] = 'wiki:Self:%s' % words[0]
+            return self.interwiki(words, pretty_url=1)
+            #return self._word_repl(words[0], words[1])
+
+        # Traditional split on space
+        words = word[1:-1].split(None, 1)
+        if len(words) == 1:
+            words = words * 2
+
+        if words[0][0] == '#':
+            # anchor link
+            return (self.formatter.url(1, words[0]) +
+                    self.formatter.text(words[1]) +
+                    self.formatter.url(0))
+
+        scheme = words[0].split(":", 1)[0]
+        if scheme == "wiki":
+            return self.interwiki(words, pretty_url=1)
+        if scheme in self.attachment_schemas:
+            return self.attachment(words, pretty_url=1)
+
+        if wikiutil.isPicture(words[1]) and re.match(self.url_rule, words[1]):
+            return (self.formatter.url(1, words[0], css='external', do_escape=0) +
+                    self.formatter.image(title=words[0], alt=words[0], src=words[1]) +
+                    self.formatter.url(0))
+        else:
+            return (self.formatter.url(1, words[0], css=scheme, do_escape=0) +
+                    self.formatter.text(words[1]) +
+                    self.formatter.url(0))
+
+
+    def _email_repl(self, word):
+        """Handle email addresses (without a leading mailto:)."""
+        return (self.formatter.url(1, "mailto:" + word, css='mailto') +
+                self.formatter.text(word) +
+                self.formatter.url(0))
+
+
+    def _ent_repl(self, word):
+        """Handle SGML entities."""
+        return self.formatter.text(word)
+        #return {'&': '&amp;',
+        #        '<': '&lt;',
+        #        '>': '&gt;'}[word]
+
+    def _ent_numeric_repl(self, word):
+        """Handle numeric (decimal and hexadecimal) SGML entities."""
+        return self.formatter.rawHTML(word)
+
+    def _ent_symbolic_repl(self, word):
+        """Handle symbolic SGML entities."""
+        return self.formatter.rawHTML(word)
+
+    def _indent_repl(self, match):
+        """Handle pure indentation (no - * 1. markup)."""
+        result = []
+        if not (self.in_li or self.in_dd):
+            self._close_item(result)
+            self.in_li = 1
+            css_class = None
+            if self.line_was_empty and not self.first_list_item:
+                css_class = 'gap'
+            result.append(self.formatter.listitem(1, css_class=css_class, style="list-style-type:none"))
+        return ''.join(result)
+
+    def _li_none_repl(self, match):
+        """Handle type=none (" .") lists."""
+        result = []
+        self._close_item(result)
+        self.in_li = 1
+        css_class = None
+        if self.line_was_empty and not self.first_list_item:
+            css_class = 'gap'
+        result.append(self.formatter.listitem(1, css_class=css_class, style="list-style-type:none"))
+        return ''.join(result)
+
+    def _li_repl(self, match):
+        """Handle bullet (" *") lists."""
+        result = []
+        self._close_item(result)
+        self.in_li = 1
+        css_class = None
+        if self.line_was_empty and not self.first_list_item:
+            css_class = 'gap'
+        result.append(self.formatter.listitem(1, css_class=css_class))
+        return ''.join(result)
+
+    def _ol_repl(self, match):
+        """Handle numbered lists."""
+        return self._li_repl(match)
+
+    def _dl_repl(self, match):
+        """Handle definition lists."""
+        result = []
+        self._close_item(result)
+        self.in_dd = 1
+        result.extend([
+            self.formatter.definition_term(1),
+            self.formatter.text(match[1:-3].lstrip(' ')),
+            self.formatter.definition_term(0),
+            self.formatter.definition_desc(1),
+        ])
+        return ''.join(result)
+
+
+    def _indent_level(self):
+        """Return current char-wise indent level."""
+        return len(self.list_indents) and self.list_indents[-1]
+
+
+    def _indent_to(self, new_level, list_type, numtype, numstart):
+        """Close and open lists."""
+        open = []   # don't make one out of these two statements!
+        close = []
+
+        if self._indent_level() != new_level and self.in_table:
+            close.append(self.formatter.table(0))
+            self.in_table = 0
+
+        while self._indent_level() > new_level:
+            self._close_item(close)
+            if self.list_types[-1] == 'ol':
+                tag = self.formatter.number_list(0)
+            elif self.list_types[-1] == 'dl':
+                tag = self.formatter.definition_list(0)
+            else:
+                tag = self.formatter.bullet_list(0)
+            close.append(tag)
+
+            del self.list_indents[-1]
+            del self.list_types[-1]
+
+            if self.list_types: # we are still in a list
+                if self.list_types[-1] == 'dl':
+                    self.in_dd = 1
+                else:
+                    self.in_li = 1
+
+        # Open new list, if necessary
+        if self._indent_level() < new_level:
+            self.list_indents.append(new_level)
+            self.list_types.append(list_type)
+
+            if self.formatter.in_p:
+                close.append(self.formatter.paragraph(0))
+
+            if list_type == 'ol':
+                tag = self.formatter.number_list(1, numtype, numstart)
+            elif list_type == 'dl':
+                tag = self.formatter.definition_list(1)
+            else:
+                tag = self.formatter.bullet_list(1)
+            open.append(tag)
+
+            self.first_list_item = 1
+            self.in_li = 0
+            self.in_dd = 0
+
+        # If list level changes, close an open table
+        if self.in_table and (open or close):
+            close[0:0] = [self.formatter.table(0)]
+            self.in_table = 0
+
+        self.in_list = self.list_types != []
+        return ''.join(close) + ''.join(open)
+
+
+    def _undent(self):
+        """Close all open lists."""
+        result = []
+        #result.append("<!-- _undent start -->\n")
+        self._close_item(result)
+        for type in self.list_types[::-1]:
+            if type == 'ol':
+                result.append(self.formatter.number_list(0))
+            elif type == 'dl':
+                result.append(self.formatter.definition_list(0))
+            else:
+                result.append(self.formatter.bullet_list(0))
+        #result.append("<!-- _undent end -->\n")
+        self.list_indents = []
+        self.list_types = []
+        return ''.join(result)
+
+
+    def _tt_repl(self, word):
+        """Handle inline code."""
+        return self.formatter.code(1) + \
+            self.formatter.text(word[3:-3]) + \
+            self.formatter.code(0)
+
+
+    def _tt_bt_repl(self, word):
+        """Handle backticked inline code."""
+        # if len(word) == 2: return "" // removed for FCK editor
+        return self.formatter.code(1, css="backtick") + \
+            self.formatter.text(word[1:-1]) + \
+            self.formatter.code(0)
+
+
+    def _getTableAttrs(self, attrdef):
+        # skip "|" and initial "<"
+        while attrdef and attrdef[0] == "|":
+            attrdef = attrdef[1:]
+        if not attrdef or attrdef[0] != "<":
+            return {}, ''
+        attrdef = attrdef[1:]
+
+        # extension for special table markup
+        def table_extension(key, parser, attrs, wiki_parser=self):
+            """ returns: tuple (found_flag, msg)
+                found_flag: whether we found something and were able to process it here
+                  true for special stuff like 100% or - or #AABBCC
+                  false for style xxx="yyy" attributes
+                msg: "" or an error msg
+            """
+            _ = wiki_parser._
+            found = False
+            msg = ''
+            if key[0] in "0123456789":
+                token = parser.get_token()
+                if token != '%':
+                    wanted = '%'
+                    msg = _('Expected "%(wanted)s" after "%(key)s", got "%(token)s"') % {
+                        'wanted': wanted, 'key': key, 'token': token}
+                else:
+                    try:
+                        dummy = int(key)
+                    except ValueError:
+                        msg = _('Expected an integer "%(key)s" before "%(token)s"') % {
+                            'key': key, 'token': token}
+                    else:
+                        found = True
+                        attrs['width'] = '"%s%%"' % key
+            elif key == '-':
+                arg = parser.get_token()
+                try:
+                    dummy = int(arg)
+                except ValueError:
+                    msg = _('Expected an integer "%(arg)s" after "%(key)s"') % {
+                        'arg': arg, 'key': key}
+                else:
+                    found = True
+                    attrs['colspan'] = '"%s"' % arg
+            elif key == '|':
+                arg = parser.get_token()
+                try:
+                    dummy = int(arg)
+                except ValueError:
+                    msg = _('Expected an integer "%(arg)s" after "%(key)s"') % {
+                        'arg': arg, 'key': key}
+                else:
+                    found = True
+                    attrs['rowspan'] = '"%s"' % arg
+            elif key == '(':
+                found = True
+                attrs['align'] = '"left"'
+            elif key == ':':
+                found = True
+                attrs['align'] = '"center"'
+            elif key == ')':
+                found = True
+                attrs['align'] = '"right"'
+            elif key == '^':
+                found = True
+                attrs['valign'] = '"top"'
+            elif key == 'v':
+                found = True
+                attrs['valign'] = '"bottom"'
+            elif key == '#':
+                arg = parser.get_token()
+                try:
+                    if len(arg) != 6: raise ValueError
+                    dummy = int(arg, 16)
+                except ValueError:
+                    msg = _('Expected a color value "%(arg)s" after "%(key)s"') % {
+                        'arg': arg, 'key': key}
+                else:
+                    found = True
+                    attrs['bgcolor'] = '"#%s"' % arg
+            return found, self.formatter.rawHTML(msg)
+
+        # scan attributes
+        attr, msg = wikiutil.parseAttributes(self.request, attrdef, '>', table_extension)
+        if msg:
+            msg = '<strong class="highlight">%s</strong>' % msg
+        #self.request.log("parseAttributes returned %r" % attr)
+        return attr, msg
+
+    def _tableZ_repl(self, word):
+        """Handle table row end."""
+        if self.in_table:
+            result = ''
+            # REMOVED: check for self.in_li, p should always close
+            if self.formatter.in_p:
+                result = self.formatter.paragraph(0)
+            result += self.formatter.table_cell(0) + self.formatter.table_row(0)
+            return result
+        else:
+            return self.formatter.text(word)
+
+    def _table_repl(self, word):
+        """Handle table cell separator."""
+        if self.in_table:
+            result = []
+            # check for attributes
+            attrs, attrerr = self._getTableAttrs(word)
+
+            # start the table row?
+            if self.table_rowstart:
+                self.table_rowstart = 0
+                result.append(self.formatter.table_row(1, attrs))
+            else:
+                # Close table cell, first closing open p
+                # REMOVED check for self.in_li, paragraph should close always!
+                if self.formatter.in_p:
+                    result.append(self.formatter.paragraph(0))
+                result.append(self.formatter.table_cell(0))
+
+            # check for adjacent cell markers
+            if word.count("|") > 2:
+                if not attrs.has_key('align') and \
+                   not (attrs.has_key('style') and 'text-align' in attrs['style'].lower()):
+                    # add center alignment if we don't have some alignment already
+                    attrs['align'] = '"center"'
+                if not attrs.has_key('colspan'):
+                    attrs['colspan'] = '"%d"' % (word.count("|")/2)
+
+            # return the complete cell markup
+            result.append(self.formatter.table_cell(1, attrs) + attrerr)
+            result.append(self._line_anchordef())
+            return ''.join(result)
+        else:
+            return self.formatter.text(word)
+
+
+    def _heading_repl(self, word):
+        """Handle section headings."""
+        import sha
+
+        h = word.strip()
+        level = 1
+        while h[level:level+1] == '=':
+            level += 1
+        depth = min(5, level)
+
+        # this is needed for Included pages
+        # TODO but it might still result in unpredictable results
+        # when included the same page multiple times
+        title_text = h[level:-level].strip()
+        pntt = self.formatter.page.page_name + title_text
+        self.titles.setdefault(pntt, 0)
+        self.titles[pntt] += 1
+
+        unique_id = ''
+        if self.titles[pntt] > 1:
+            unique_id = '-%d' % self.titles[pntt]
+        result = self._closeP()
+        result += self.formatter.heading(1, depth, id="head-"+sha.new(pntt.encode(config.charset)).hexdigest()+unique_id)
+
+        return (result + self.formatter.text(title_text) +
+                self.formatter.heading(0, depth))
+
+    def _processor_repl(self, word):
+        """Handle processed code displays."""
+        if word[:3] == '{{{':
+            word = word[3:]
+
+        self.processor = None
+        self.processor_name = None
+        self.processor_is_parser = 0
+        s_word = word.strip()
+        if s_word == '#!':
+            # empty bang paths lead to a normal code display
+            # can be used to escape real, non-empty bang paths
+            word = ''
+            self.in_pre = 3
+            return self._closeP() + self.formatter.preformatted(1)
+        elif s_word[:2] == '#!':
+            # First try to find a processor for this (will go away in 2.0)
+            processor_name = s_word[2:].split()[0]
+            self.setProcessor(processor_name)
+
+        if self.processor:
+            self.processor_name = processor_name
+            self.in_pre = 2
+            self.colorize_lines = [word]
+            return ''
+        elif s_word:
+            self.in_pre = 3
+            return self._closeP() + self.formatter.preformatted(1) + \
+                   self.formatter.text(s_word + ' (-)')
+        else:
+            self.in_pre = 1
+            return ''
+
+    def _pre_repl(self, word):
+        """Handle code displays."""
+        word = word.strip()
+        if word == '{{{' and not self.in_pre:
+            self.in_pre = 3
+            return self._closeP() + self.formatter.preformatted(self.in_pre)
+        elif word == '}}}' and self.in_pre:
+            self.in_pre = 0
+            self.inhibit_p = 0
+            return self.formatter.preformatted(self.in_pre)
+        return self.formatter.text(word)
+
+
+    def _smiley_repl(self, word):
+        """Handle smileys."""
+        return self.formatter.smiley(word)
+
+    _smileyA_repl = _smiley_repl
+
+
+    def _comment_repl(self, word):
+        # if we are in a paragraph, we must close it so that normal text following
+        # in the line below the comment will reopen a new paragraph.
+        if self.formatter.in_p:
+            self.formatter.paragraph(0)
+        self.line_is_empty = 1 # markup following comment lines treats them as if they were empty
+        return self.formatter.comment(word)
+
+    def _closeP(self):
+        if self.formatter.in_p:
+            return self.formatter.paragraph(0)
+        return ''
+
+    def _macro_repl(self, word):
+        """Handle macros ([[macroname]])."""
+        macro_name = word[2:-2]
+        self.inhibit_p = 0 # 1 fixes UserPreferences, 0 fixes paragraph formatting for macros
+
+        # check for arguments
+        args = None
+        if macro_name.count("("):
+            macro_name, args = macro_name.split('(', 1)
+            args = args[:-1]
+
+        # create macro instance
+        if self.macro is None:
+            self.macro = wikimacro.Macro(self)
+        return self.formatter.macro(self.macro, macro_name, args)
+
+    def scan(self, scan_re, line):
+        """ Scans one line
+
+        Append text before match, invoke replace() with match, and add text after match.
+        """
+        result = []
+        lastpos = 0
+
+        ###result.append(u'<span class="info">[scan: <tt>"%s"</tt>]</span>' % line)
+
+        for match in scan_re.finditer(line):
+            # Add text before the match
+            if lastpos < match.start():
+
+                ###result.append(u'<span class="info">[add text before match: <tt>"%s"</tt>]</span>' % line[lastpos:match.start()])
+
+                if not (self.inhibit_p or self.in_pre or self.formatter.in_p):
+                    result.append(self.formatter.paragraph(1, css_class="line862"))
+                result.append(self.formatter.text(line[lastpos:match.start()]))
+
+            # Replace match with markup
+            if not (self.inhibit_p or self.in_pre or self.formatter.in_p or
+                    self.in_table or self.in_list):
+                result.append(self.formatter.paragraph(1, css_class="line867"))
+            result.append(self.replace(match))
+            lastpos = match.end()
+
+        ###result.append('<span class="info">[no match, add rest: <tt>"%s"<tt>]</span>' % line[lastpos:])
+
+        # Add paragraph with the remainder of the line
+        if not (self.in_pre or self.in_li or self.in_dd or self.inhibit_p or
+                self.formatter.in_p) and lastpos < len(line):
+            result.append(self.formatter.paragraph(1, css_class="line874"))
+        result.append(self.formatter.text(line[lastpos:]))
+        return u''.join(result)
+
+    def replace(self, match):
+        """ Replace match using type name """
+        result = []
+        for type, hit in match.groupdict().items():
+            if hit is not None and type != "hmarker":
+
+                ###result.append(u'<span class="info">[replace: %s: "%s"]</span>' % (type, hit))
+                if self.in_pre and type not in ['pre', 'ent']:
+                    return self.formatter.text(hit)
+                else:
+                    # Open p for certain types
+                    if not (self.inhibit_p or self.formatter.in_p
+                            or self.in_pre or (type in self.no_new_p_before)):
+                        result.append(self.formatter.paragraph(1, css_class="line891"))
+
+                    # Get replace method and replece hit
+                    replace = getattr(self, '_' + type + '_repl')
+                    result.append(replace(hit))
+                    return ''.join(result)
+        else:
+            # We should never get here
+            import pprint
+            raise Exception("Can't handle match " + `match`
+                + "\n" + pprint.pformat(match.groupdict())
+                + "\n" + pprint.pformat(match.groups()) )
+
+        return ""
+
+    def _line_anchordef(self):
+        if self.line_anchors and not self.line_anchor_printed:
+            self.line_anchor_printed = 1
+            return self.formatter.line_anchordef(self.lineno)
+        else:
+            return ''
+
+    def format(self, formatter):
+        """ For each line, scan through looking for magic
+            strings, outputting verbatim any intervening text.
+        """
+        self.formatter = formatter
+        self.hilite_re = self.formatter.page.hilite_re
+
+        # prepare regex patterns
+        rules = self.formatting_rules.replace('\n', '|')
+        if self.cfg.bang_meta:
+            rules = ur'(?P<notword>!%(word_rule)s)|%(rules)s' % {
+                'word_rule': self.word_rule,
+                'rules': rules,
+            }
+        self.request.clock.start('compile_huge_and_ugly')
+        scan_re = re.compile(rules, re.UNICODE)
+        number_re = re.compile(self.ol_rule, re.UNICODE)
+        term_re = re.compile(self.dl_rule, re.UNICODE)
+        indent_re = re.compile("^\s*", re.UNICODE)
+        eol_re = re.compile(r'\r?\n', re.UNICODE)
+        self.request.clock.stop('compile_huge_and_ugly')
+
+        # get text and replace TABs
+        rawtext = self.raw.expandtabs()
+
+        # go through the lines
+        self.lineno = self.start_line
+        self.lines = eol_re.split(rawtext)
+        self.line_is_empty = 0
+
+        self.in_processing_instructions = 1
+
+        # Main loop
+        for line in self.lines:
+            self.lineno += 1
+            self.line_anchor_printed = 0
+            if not self.in_table:
+                self.request.write(self._line_anchordef())
+            self.table_rowstart = 1
+            self.line_was_empty = self.line_is_empty
+            self.line_is_empty = 0
+            self.first_list_item = 0
+            self.inhibit_p = 0
+
+            # ignore processing instructions
+            if self.in_processing_instructions:
+                found = False
+                for pi in ("##", "#format", "#refresh", "#redirect", "#deprecated",
+                           "#pragma", "#form", "#acl", "#language"):
+                    if line.lower().startswith(pi):
+                        self.request.write(self.formatter.comment(line))
+                        found = True
+                        break
+                if not found:
+                    self.in_processing_instructions = 0
+                else:
+                    continue # do not parse this line
+            if self.in_pre:
+                # TODO: move this into function
+                # still looking for processing instructions
+                # TODO: use strings for pre state, not numbers
+                if self.in_pre == 1:
+                    self.processor = None
+                    self.processor_is_parser = 0
+                    processor_name = ''
+                    if (line.strip()[:2] == "#!"):
+                        processor_name = line.strip()[2:].split()[0]
+                        self.setProcessor(processor_name)
+
+                    if self.processor:
+                        self.in_pre = 2
+                        self.colorize_lines = [line]
+                        self.processor_name = processor_name
+                        continue
+                    else:
+                        self.request.write(self._closeP() +
+                                           self.formatter.preformatted(1))
+                        self.in_pre = 3
+                if self.in_pre == 2:
+                    # processing mode
+                    endpos = line.find("}}}")
+                    if endpos == -1:
+                        self.colorize_lines.append(line)
+                        continue
+                    if line[:endpos]:
+                        self.colorize_lines.append(line[:endpos])
+
+                    # Close p before calling processor
+                    # TODO: do we really need this?
+                    self.request.write(self._closeP())
+                    res = self.formatter.processor(self.processor_name,
+                                                   self.colorize_lines,
+                                                   self.processor_is_parser)
+                    self.request.write(res)
+                    del self.colorize_lines
+                    self.in_pre = 0
+                    self.processor = None
+
+                    # send rest of line through regex machinery
+                    line = line[endpos+3:]
+                    if not line.strip(): # just in the case "}}} " when we only have blanks left...
+                        continue
+            else:
+                # we don't have \n as whitespace any more
+                # This is the space between lines we join to one paragraph
+                line += ' '
+
+                # Paragraph break on empty lines
+                if not line.strip():
+                    if self.in_table:
+                        self.request.write(self.formatter.table(0))
+                        self.request.write(self._line_anchordef())
+                        self.in_table = 0
+                    # CHANGE: removed check for not self.list_types
+                    # p should close on every empty line
+                    if self.formatter.in_p:
+                        self.request.write(self.formatter.paragraph(0))
+                    self.line_is_empty = 1
+                    continue
+
+                # Check indent level
+                indent = indent_re.match(line)
+                indlen = len(indent.group(0))
+                indtype = "ul"
+                numtype = None
+                numstart = None
+                if indlen:
+                    match = number_re.match(line)
+                    if match:
+                        numtype, numstart = match.group(0).strip().split('.')
+                        numtype = numtype[0]
+
+                        if numstart and numstart[0] == "#":
+                            numstart = int(numstart[1:])
+                        else:
+                            numstart = None
+
+                        indtype = "ol"
+                    else:
+                        match = term_re.match(line)
+                        if match:
+                            indtype = "dl"
+
+                # output proper indentation tags
+                self.request.write(self._indent_to(indlen, indtype, numtype, numstart))
+
+                # Table mode
+                # TODO: move into function?
+                if (not self.in_table and line[indlen:indlen + 2] == "||"
+                    and line[-3:] == "|| " and len(line) >= 5 + indlen):
+                    # Start table
+                    if self.list_types and not self.in_li:
+                        self.request.write(self.formatter.listitem(1, style="list-style-type:none"))
+                        ## CHANGE: no automatic p on li
+                        ##self.request.write(self.formatter.paragraph(1))
+                        self.in_li = 1
+
+                    # CHANGE: removed check for self.in_li
+                    # paragraph should end before table, always!
+                    if self.formatter.in_p:
+                        self.request.write(self.formatter.paragraph(0))
+                    attrs, attrerr = self._getTableAttrs(line[indlen+2:])
+                    self.request.write(self.formatter.table(1, attrs) + attrerr)
+                    self.in_table = True # self.lineno
+                elif (self.in_table and not
+                      # intra-table comments should not break a table
+                      (line[:2] == "##" or
+                       line[indlen:indlen + 2] == "||" and
+                       line[-3:] == "|| " and
+                       len(line) >= 5 + indlen)):
+
+                    # Close table
+                    self.request.write(self.formatter.table(0))
+                    self.request.write(self._line_anchordef())
+                    self.in_table = 0
+
+            # Scan line, format and write
+            formatted_line = self.scan(scan_re, line)
+            self.request.write(formatted_line)
+
+            if self.in_pre == 3:
+                self.request.write(self.formatter.linebreak())
+
+        # Close code displays, paragraphs, tables and open lists
+        self.request.write(self._undent())
+        if self.in_pre: self.request.write(self.formatter.preformatted(0))
+        if self.formatter.in_p: self.request.write(self.formatter.paragraph(0))
+        if self.in_table: self.request.write(self.formatter.table(0))
+
+    # --------------------------------------------------------------------
+    # Private helpers
+
+    def setProcessor(self, name):
+        """ Set processer to either processor or parser named 'name' """
+        cfg = self.request.cfg
+        try:
+            self.processor = wikiutil.importPlugin(cfg, "processor", name,
+                                                   "process")
+            self.processor_is_parser = 0
+        except wikiutil.PluginMissingError:
+            try:
+                self.processor = wikiutil.importPlugin(cfg, "parser", name,
+                                                   "Parser")
+                self.processor_is_parser = 1
+            except wikiutil.PluginMissingError:
+                self.processor = None
+
+
--- a/MoinMoin/theme/__init__.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/theme/__init__.py	Tue Aug 21 15:47:56 2007 +0200
@@ -298,7 +298,7 @@
         """ Split navibar links into pagename, link to page
 
         Admin or user might want to use shorter navibar items by using
-        the [page title] or [url title] syntax. In this case, we don't
+        the [[page|title]] or [[url|title]] syntax. In this case, we don't
         use localization, and the links goes to page or to the url, not
         the localized version of page.
 
@@ -307,7 +307,7 @@
             * WikiName:PageName
             * wiki:WikiName:PageName
             * url
-            * all targets as seen above with title: [target title]
+            * all targets as seen above with title: [[target|title]]
 
         @param text: the text used in config or user preferences
         @rtype: tuple
@@ -317,16 +317,17 @@
         fmt = request.formatter
         title = None
 
-        # Handle [pagename title] or [url title] formats
-        if text.startswith('[') and text.endswith(']'):
-            text = text[1:-1].strip()
+        # Handle [[pagename|title]] or [[url|title]] formats
+        if text.startswith('[[') and text.endswith(']]'):
+            text = text[2:-2]
             try:
-                pagename, title = text.split(' ', 1)
-                title = title.lstrip()
+                pagename, title = text.split('|', 1)
+                pagename = pagename.strip()
+                title = title.strip()
                 localize = 0
             except (ValueError, TypeError):
                 # Just use the text as is.
-                pagename = text
+                pagename = text.strip()
         else:
             pagename = text
 
@@ -344,9 +345,9 @@
 
         # try handling interwiki links
         try:
-            interwiki, page = pagename.split(':', 1)
+            interwiki, page = wikiutil.split_interwiki(pagename)
             thiswiki = request.cfg.interwikiname
-            if interwiki == thiswiki:
+            if interwiki == thiswiki or interwiki == 'Self':
                 pagename = page
             else:
                 if not title:
@@ -478,7 +479,7 @@
     def get_icon(self, icon):
         """ Return icon data from self.icons
 
-        If called from [[Icon(file)]] we have a filename, not a
+        If called from <<Icon(file)>> we have a filename, not a
         key. Using filenames is deprecated, but for now, we simulate old
         behavior.
 
@@ -587,8 +588,8 @@
                 items = []
                 for pagename in trail:
                     try:
-                        interwiki, page = pagename.split(":", 1)
-                        if request.cfg.interwikiname != interwiki:
+                        interwiki, page = wikiutil.split_interwiki(pagename)
+                        if interwiki != request.cfg.interwikiname and interwiki != 'Self':
                             link = (self.request.formatter.interwikilink(True, interwiki, page) +
                                     self.shortenPagename(page) +
                                     self.request.formatter.interwikilink(False, interwiki, page))
--- a/MoinMoin/user.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/user.py	Tue Aug 21 15:47:56 2007 +0200
@@ -987,9 +987,9 @@
             if wikiutil.isStrictWikiname(self.name):
                 markup = pagename
             else:
-                markup = '["%s"]' % pagename
+                markup = '[[%s]]' % pagename
         else:
-            markup = '%s:%s' % (wikiname, pagename) # TODO: support spaces in pagename
+            markup = '[[%s:%s]]' % (wikiname, pagename)
         return markup
 
     def signature(self):
--- a/MoinMoin/userprefs/notification.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/userprefs/notification.py	Tue Aug 21 15:47:56 2007 +0200
@@ -156,7 +156,7 @@
         notifylist = self.request.user.getSubscriptionList()
 
         self.make_row(
-            html.Raw(_('Subscribed wiki pages[[BR]](one regex per line)')),
+            html.Raw(_('Subscribed wiki pages<<BR>>(one regex per line)')),
             [html.TEXTAREA(name="subscribed_pages", rows="6", cols="50").append(
                 '\n'.join(notifylist)), ],
             valign="top"
--- a/MoinMoin/wikisync.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/wikisync.py	Tue Aug 21 15:47:56 2007 +0200
@@ -166,7 +166,7 @@
         self.verbose = verbose
         _ = self.request.getText
 
-        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, '%s:""' % (interwikiname, ))
+        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_interwiki(self.request, interwikiname, '')
         self.wiki_url = wikiutil.mapURL(self.request, wikiurl)
         self.valid = not wikitag_bad
         self.xmlrpc_url = self.wiki_url + "?action=xmlrpc2"
--- a/MoinMoin/wikiutil.py	Tue Aug 21 15:45:24 2007 +0200
+++ b/MoinMoin/wikiutil.py	Tue Aug 21 15:47:56 2007 +0200
@@ -486,21 +486,9 @@
 
 # Quoting of wiki names, file names, etc. (in the wiki markup) -----------------------------------
 
-# don't ever change this
+# don't ever change this - DEPRECATED, only needed for 1.5 > 1.6 migration conversion
 QUOTE_CHARS = u'"'
 
-def quoteName(name):
-    """ put quotes around a given name """
-    return '"%s"' % name.replace('"', '""')
-
-def unquoteName(name):
-    """ if there are quotes around the name, strip them """
-    if not name:
-        return name
-    if '"' == name[0] == name[-1]:
-        return name[1:-1].replace('""', '"')
-    else:
-        return name
 
 #############################################################################
 ### InterWiki
@@ -590,56 +578,54 @@
     return _interwiki_list
 
 def split_wiki(wikiurl):
-    """ Split a wiki url, e.g:
+    """
+    Split a wiki url.
 
-    'MoinMoin:FrontPage' -> "MoinMoin", "FrontPage", ""
-    'FrontPage' -> "Self", "FrontPage", ""
-    'MoinMoin:"Page with blanks" link title' -> "MoinMoin", "Page with blanks", "link title"
-
-    can also be used for:
-
-    'attachment:"filename with blanks.txt" other title' -> "attachment", "filename with blanks.txt", "other title"
+    *** DEPRECATED FUNCTION FOR OLD 1.5 SYNTAX - ONLY STILL HERE FOR THE 1.5 -> 1.6 MIGRATION ***
+    Use split_interwiki(), see below.
 
     @param wikiurl: the url to split
     @rtype: tuple
-    @return: (wikiname, pagename, linktext)
+    @return: (tag, tail)
     """
+    # !!! use a regex here!
     try:
-        wikiname, rest = wikiurl.split(":", 1) # e.g. MoinMoin:FrontPage
+        wikitag, tail = wikiurl.split(":", 1)
     except ValueError:
         try:
-            wikiname, rest = wikiurl.split("/", 1) # for what is this used?
+            wikitag, tail = wikiurl.split("/", 1)
         except ValueError:
-            wikiname, rest = 'Self', wikiurl
-    if rest:
-        if rest[0] == '"': # quoted pagename
-            idx = 1
-            max = len(rest)
-            while idx < max:
-                if idx + 1 < max:
-                    next = rest[idx + 1]
-                else:
-                    next = None
-                if next == rest[idx] == '"':
-                    idx += 2
-                    continue
-                if next != '"' and rest[idx] == '"':
-                    break
-                idx += 1
-            pagename_linktext = rest[1:idx].replace('""', '"'), rest[idx+1:]
-        else: # not quoted, split on whitespace
-            pagename_linktext = rest.split(None, 1)
-    else:
-        pagename_linktext = "", ""
-    if len(pagename_linktext) == 1:
-        pagename, linktext = pagename_linktext[0], ""
-    else:
-        pagename, linktext = pagename_linktext
-    linktext = linktext.strip()
-    return wikiname, pagename, linktext
+            wikitag, tail = 'Self', wikiurl
+    return wikitag, tail
+
+def split_interwiki(wikiurl):
+    """ Split a interwiki name, into wikiname and pagename, e.g:
+
+    'MoinMoin:FrontPage' -> "MoinMoin", "FrontPage"
+    'FrontPage' -> "Self", "FrontPage"
+    'MoinMoin:Page with blanks' -> "MoinMoin", "Page with blanks"
+    'MoinMoin:' -> "MoinMoin", ""
+
+    can also be used for:
+
+    'attachment:filename with blanks.txt' -> "attachment", "filename with blanks.txt"
+
+    @param wikiurl: the url to split
+    @rtype: tuple
+    @return: (wikiname, pagename)
+    """
+    try:
+        wikiname, pagename = wikiurl.split(":", 1)
+    except ValueError:
+        wikiname, pagename = 'Self', wikiurl
+    return wikiname, pagename
 
 def resolve_wiki(request, wikiurl):
-    """ Resolve an interwiki link.
+    """
+    Resolve an interwiki link.
+
+    *** DEPRECATED FUNCTION FOR OLD 1.5 SYNTAX - ONLY STILL HERE FOR THE 1.5 -> 1.6 MIGRATION ***
+    Use resolve_interwiki(), see below.
 
     @param request: the request object
     @param wikiurl: the InterWiki:PageName link
@@ -647,7 +633,25 @@
     @return: (wikitag, wikiurl, wikitail, err)
     """
     _interwiki_list = load_wikimap(request)
-    wikiname, pagename, linktext = split_wiki(wikiurl)
+    # split wiki url
+    wikiname, pagename = split_wiki(wikiurl)
+
+    # return resolved url
+    if wikiname in _interwiki_list:
+        return (wikiname, _interwiki_list[wikiname], pagename, False)
+    else:
+        return (wikiname, request.getScriptname(), "/InterWiki", True)
+
+def resolve_interwiki(request, wikiname, pagename):
+    """ Resolve an interwiki reference (wikiname:pagename).
+
+    @param request: the request object
+    @param wikiname: interwiki wiki name
+    @param pagename: interwiki page name
+    @rtype: tuple
+    @return: (wikitag, wikiurl, wikitail, err)
+    """
+    _interwiki_list = load_wikimap(request)
     if wikiname in _interwiki_list:
         return (wikiname, _interwiki_list[wikiname], pagename, False)
     else:
@@ -857,7 +861,7 @@
     if re.match(Parser.word_rule + "$", pagename):
         return pagename
     else:
-        return u'["%s"]' % pagename # XXX use quoteName(pagename) later
+        return u'[[%s]]' % pagename
 
 #############################################################################
 ### mimetype support