changeset 841:3157ddeb3667

Merge with main.
author Franz Pletz <fpletz AT franz-pletz DOT org>
date Tue, 13 Jun 2006 17:46:57 +0200
parents faebfa285206 (current diff) e9e09bf11c82 (diff)
children 4bd5f5f8f95a
files
diffstat 15 files changed, 197 insertions(+), 200 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/action/MyPages.py	Sun Jun 11 11:04:38 2006 +0200
+++ b/MoinMoin/action/MyPages.py	Tue Jun 13 17:46:57 2006 +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_wiki(request, '%s:"%s"' % interwiki)
         wikiurl = wikiutil.mapURL(request, wikiurl)
         homepageurl = wikiutil.join_wiki(wikiurl, wikitail)
         request.http_redirect('%s?action=MyPages' % homepageurl)
--- a/MoinMoin/action/fckdialog.py	Sun Jun 11 11:04:38 2006 +0200
+++ b/MoinMoin/action/fckdialog.py	Tue Jun 13 17:46:57 2006 +0200
@@ -230,8 +230,8 @@
         page_list = ""
     
     # list of interwiki names
-    wikiutil.resolve_wiki(request, "Self:FrontPage")
-    interwiki = request.cfg._interwiki_list.keys()
+    interwiki_list = wikiutil.load_wikimap(request)
+    interwiki = interwiki_list.keys()
     interwiki.sort()
     iwpreferred = request.cfg.interwiki_preferred
     if not iwpreferred or iwpreferred and iwpreferred[-1] != None:
--- a/MoinMoin/converter/text_html_text_moin_wiki.py	Sun Jun 11 11:04:38 2006 +0200
+++ b/MoinMoin/converter/text_html_text_moin_wiki.py	Tue Jun 13 17:46:57 2006 +0200
@@ -392,6 +392,18 @@
 ]>
 '''
 
+def pagename_from_url(url_frag):
+    """ url is a fragment of an URL we extract the pagename from by URL-unqouting
+        and possible adding quotes around the pagename if we detect blanks in it.
+    """
+    pagename = wikiutil.url_unquote(url_frag)
+    if " " in pagename:
+        if not '"' in pagename:
+            pagename = '"%s"' % pagename
+        elif not "'" in pagename:
+            pagename = "'%s'" % pagename
+    return pagename
+
 class ConvertError(error.FatalError):
     """ Raise when html to wiki conversion fails """
     name = "MoinMoin Convert Error"
@@ -1088,15 +1100,15 @@
                 wikitag, wikiurl, wikitail, err = wikiutil.resolve_wiki(
                     self.request, title + ":")
                 if not err and href.startswith(wikiurl):
-                    pagename = href[len(wikiurl):].lstrip('/')
+                    pagename = pagename_from_url(href[len(wikiurl):].lstrip('/'))
                     interwikiname = "%s:%s" % (wikitag, pagename)
                 else: 
                     raise ConvertError("Invalid InterWiki link: '%s'" % href)
             elif class_ == "badinterwiki" and title:
                 if href == "/": # we used this as replacement for empty href
                     href = ""
-                pagename = href
-                interwikiname = "%s:%s" % (title, href)
+                pagename = pagename_from_url(href)
+                interwikiname = "%s:%s" % (title, pagename)
             if interwikiname and pagename == text: 
                 self.text.append("%s" % interwikiname)
                 return
@@ -1122,7 +1134,7 @@
                     self.text.extend([self.white_space, title, self.white_space])
             # wiki link
             elif href.startswith(scriptname):
-                pagename = href[len(scriptname):].replace('_', ' ')
+                pagename = href[len(scriptname):]
                 pagename = pagename.lstrip('/')    # XXX temp fix for generated pagenames starting with /
                 if text == pagename:
                     self.text.append(wikiutil.pagelinkmarkup(pagename))
--- a/MoinMoin/formatter/__init__.py	Sun Jun 11 11:04:38 2006 +0200
+++ b/MoinMoin/formatter/__init__.py	Tue Jun 13 17:46:57 2006 +0200
@@ -94,7 +94,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_wiki(self.request, '%s:"%s"' % (interwiki, pagename))
         if wikitag == 'Self' or wikitag == self.request.cfg.interwikiname:
             if wikitail.find('#') > -1:
                 wikitail, kw['anchor'] = wikitail.split('#', 1)
--- a/MoinMoin/formatter/text_docbook.py	Sun Jun 11 11:04:38 2006 +0200
+++ b/MoinMoin/formatter/text_docbook.py	Tue Jun 13 17:46:57 2006 +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_wiki(self.request, '%s:"%s"' % (interwiki, pagename))
         wikiurl = wikiutil.mapURL(self.request, wikiurl)
         href = wikiutil.join_wiki(wikiurl, wikitail)
 
--- a/MoinMoin/formatter/text_html.py	Sun Jun 11 11:04:38 2006 +0200
+++ b/MoinMoin/formatter/text_html.py	Tue Jun 13 17:46:57 2006 +0200
@@ -502,7 +502,7 @@
         """
         @keyword title: override using the interwiki wikiname as title
         """
-        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, '%s:%s' % (interwiki, pagename))
+        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, '%s:"%s"' % (interwiki, pagename))
         wikiurl = wikiutil.mapURL(self.request, wikiurl)
         if wikitag == 'Self': # for own wiki, do simple links
             if on:
@@ -626,6 +626,7 @@
     def attachment_link(self, url, text, **kw):
         _ = self.request.getText
         pagename, filename = AttachFile.absoluteName(url, self.page.page_name)
+        #self.request.log("attachment_link: url %s pagename %s filename %s" % (url, pagename, filename))
         fname = wikiutil.taintfilename(filename)
         fpath = AttachFile.getFilename(self.request, pagename, fname)
         if not os.path.exists(fpath):
@@ -694,8 +695,7 @@
 
         # check for map file
         if os.path.exists(mappath):
-            # we have a image map. inline it and add a map ref
-            # to the img tag
+            # we have a image map. inline it and add a map ref to the img tag
             try:
                 map = file(mappath, 'r').read()
             except IOError:
--- a/MoinMoin/macro/__init__.py	Sun Jun 11 11:04:38 2006 +0200
+++ b/MoinMoin/macro/__init__.py	Tue Jun 13 17:46:57 2006 +0200
@@ -335,13 +335,10 @@
         
     def _macro_InterWiki(self, args):
         from StringIO import StringIO
-
-        # load interwiki list
-        dummy = wikiutil.resolve_wiki(self.request, '')
-
+        interwiki_list = wikiutil.load_wikimap(self.request)
         buf = StringIO()
         buf.write('<dl>')
-        list = self.cfg._interwiki_list.items() # this is where we cached it
+        list = interwiki_list.items() # this is where we cached it
         list.sort()
         for tag, url in list:
             buf.write('<dt><tt><a href="%s">%s</a></tt></dt>' % (
@@ -351,7 +348,6 @@
             else:
                 buf.write('<dd><tt>%s</tt></dd>' % url)
         buf.write('</dl>')
-
         return self.formatter.rawHTML(buf.getvalue())
 
     def _macro_PageCount(self, args):
--- a/MoinMoin/parser/text_moin_wiki.py	Sun Jun 11 11:04:38 2006 +0200
+++ b/MoinMoin/parser/text_moin_wiki.py	Tue Jun 13 17:46:57 2006 +0200
@@ -30,8 +30,12 @@
 
     # some common strings
     PARENT_PREFIX = wikiutil.PARENT_PREFIX
+    sq_string = ur"('.*?')" # single quoted string
+    dq_string = ur"(\".*?\")" # double quoted string
+    q_string = ur"(%s|%s)" % (sq_string, dq_string) # quoted string
     attachment_schemas = ["attachment", "inline", "drawing"]
     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 ''))
@@ -43,10 +47,12 @@
         '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_rule = ur'%(url_guard)s(%(url)s)\:(([^\s\<%(punct)s]|([%(punctnq)s][^\s\<%(punct)s]))+|%(q_string)s)' % {
         'url_guard': u'(^|(?<!\w))',
         'url': url_pattern,
         'punct': punct_pattern,
+        'punctnq': punct_no_quote_pattern,
+        'q_string': q_string,
     }
 
     ol_rule = ur"^\s+(?:[0-9]+|[aAiI])\.(?:#\d+)?\s"
@@ -78,7 +84,7 @@
 (?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<interwiki>[A-Z][a-zA-Z]+\:(%(q_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)
@@ -87,11 +93,12 @@
 (?P<smileyA>^(%(smiley)s)(?=\s))
 (?P<ent_symbolic>&[a-zA-Z]+;)
 (?P<ent>[<>&])
-(?P<wikiname_bracket>\[".*?"\])
+(?P<wikiname_bracket>\[%(q_string)s.*?\])
 (?P<tt_bt>`.*?`)"""  % {
 
         'url': url_pattern,
         'punct': punct_pattern,
+        'q_string': q_string,
         'ol_rule': ol_rule,
         'dl_rule': dl_rule,
         'url_rule': url_rule,
@@ -154,81 +161,46 @@
         #result.append("<!-- close item end -->\n")
 
 
-    def interwiki(self, url_and_text, **kw):
+    def interwiki(self, target_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
+        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))
 
-        # 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)
+        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(wikitail):
+        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)
 
-        # link to self?
-        if wikitag is None:
-            return self._word_repl(wikitail)
-              
-        return (self.formatter.interwikilink(1, tag, tail) + 
+        return (self.formatter.interwikilink(1, wikiname, pagename) + 
                 self.formatter.text(text) +
-                self.formatter.interwikilink(0, tag, tail))
+                self.formatter.interwikilink(0, wikiname, pagename))
 
-    def attachment(self, url_and_text, **kw):
-        """ This gets called on attachment URLs.
-        """
+    def attachment(self, target_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
+        #self.request.log("attachment: target_and_text %s" % target_and_text)
+        scheme, fname, text = wikiutil.split_wiki(target_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
+        if scheme == 'drawing':
+            return self.formatter.attachment_drawing(fname, text)
 
-        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)
+        # 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 inline:
-            return self.formatter.attachment_inlined(url, text)
+        if scheme == 'inline':
+            return self.formatter.attachment_inlined(fname, text)
 
-        return self.formatter.attachment_link(url, text)
+        return self.formatter.attachment_link(fname, text)
 
     def _u_repl(self, word):
         """Handle underline."""
@@ -365,17 +337,17 @@
         if wikitag_bad:
             return self.formatter.text(word)
         else:
-            return self.interwiki(["wiki:" + word])
-
+            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])
+            return self.interwiki(word)
+
         if scheme in self.attachment_schemas:
-            return self.attachment([word])
+            return self.attachment(word)
 
         if wikiutil.isPicture(word):
             word = wikiutil.mapURL(self.request, word)
@@ -389,43 +361,58 @@
                     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)
+    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 "'\"": # this is quoted
+            # split on closing quote
+            target, linktext = word[1:].split(first_char, 1)
+        else: # not quoted
+            # split on whitespace
+            target, linktext = word.split(None, 1)
+        if target:
+            linktext = linktext.strip()
+            return self._word_repl(target, linktext)
         else:
-            return self.formatter.text(word)
+            return self.formatter.text(text)
 
 
     def _url_bracket_repl(self, word):
         """Handle bracketed URLs."""
-
-        # Local extended link?
-        if word[1] == ':':
-            words = word[2:-1].split(':', 1)
+        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
-            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
+            target_and_text = 'wiki:Self:"%s" %s' % tuple(words)
+            return self.interwiki(target_and_text, pretty_url=1)
 
-        if words[0][0] == '#':
-            # anchor link
-            return (self.formatter.url(1, words[0]) +
-                    self.formatter.text(words[1]) +
-                    self.formatter.url(0))
+        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
 
-        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 words[0].startswith('#'): # anchor link
+                return (self.formatter.url(1, words[0]) +
+                        self.formatter.text(words[1]) +
+                        self.formatter.url(0))
+        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
 
         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) +
@@ -888,7 +875,7 @@
         """ Replace match using type name """
         result = []
         for type, hit in match.groupdict().items():
-            if hit is not None and type != "hmarker":
+            if hit is not None and not type in ["hmarker", ]:
                 
                 ###result.append(u'<span class="info">[replace: %s: "%s"]</span>' % (type, hit))
                 if self.in_pre and type not in ['pre', 'ent']:
--- a/MoinMoin/request/__init__.py	Sun Jun 11 11:04:38 2006 +0200
+++ b/MoinMoin/request/__init__.py	Tue Jun 13 17:46:57 2006 +0200
@@ -803,9 +803,6 @@
     def normalizePagename(self, name):
         """ Normalize page name 
 
-        Convert '_' to spaces - allows using nice URLs with spaces, with no
-        need to quote.
-
         Prevent creating page names with invisible characters or funny
         whitespace that might confuse the users or abuse the wiki, or
         just does not make sense.
@@ -816,9 +813,6 @@
         @rtype: unicode
         @return: decoded and sanitized page name
         """
-        # Replace underscores with spaces
-        name = name.replace(u'_', u' ')
-
         # Strip invalid characters
         name = config.page_invalid_chars_regex.sub(u'', name)
 
--- a/MoinMoin/search.py	Sun Jun 11 11:04:38 2006 +0200
+++ b/MoinMoin/search.py	Tue Jun 13 17:46:57 2006 +0200
@@ -393,7 +393,6 @@
         @param use_re: treat pattern as re of plain text, bool
         @param case: do case sensitive search, bool 
         """
-        pattern = pattern.replace("_", " ")
         # used for search in links
         self._pattern = pattern
         # used for search in text
--- a/MoinMoin/theme/__init__.py	Sun Jun 11 11:04:38 2006 +0200
+++ b/MoinMoin/theme/__init__.py	Tue Jun 13 17:46:57 2006 +0200
@@ -347,10 +347,6 @@
         except ValueError:
             pass
                   
-        # Normalize page names, replace '_' with ' '. Usually
-        # all names use spaces internally, but for
-        # [name_with_spaces label] we must save the underscores
-        # until this point.
         pagename = request.normalizePagename(pagename)
         link = Page(request, pagename).link_to(request, title)
 
@@ -555,9 +551,6 @@
                 for pagename in trail:
                     try:
                         interwiki, page = pagename.split(":", 1)
-                        # Items in trail are saved as valid interwiki
-                        # links, using _ for spaces.
-                        page = page.replace('_', ' ')
                         if request.cfg.interwikiname != interwiki:
                             link = (self.request.formatter.interwikilink(True, interwiki, page) +
                                     self.shortenPagename(page) +
--- a/MoinMoin/user.py	Sun Jun 11 11:04:38 2006 +0200
+++ b/MoinMoin/user.py	Tue Jun 13 17:46:57 2006 +0200
@@ -136,9 +136,9 @@
     @rtype: unicode
     @return: user name that can be used in acl lines
     """
-    name = name.replace('_', ' ') # we treat _ as a blank
-    username_allowedchars = "'@.-" # ' for names like O'Brian or email addresses.
-                                   # "," and ":" must not be allowed (ACL delimiters).
+    username_allowedchars = "'@.-_" # ' for names like O'Brian or email addresses.
+                                    # "," and ":" must not be allowed (ACL delimiters).
+                                    # We also allow _ in usernames for nicer URLs.
     # Strip non alpha numeric characters (except username_allowedchars), keep white space
     name = ''.join([c for c in name if c.isalnum() or c.isspace() or c in username_allowedchars])
 
@@ -155,7 +155,6 @@
     @param name: user name, unicode
     """
     normalized = normalizeName(name)
-    name = name.replace('_', ' ') # we treat _ as a blank
     return (name == normalized) and not wikiutil.isGroupPage(request, name)
 
 
@@ -812,8 +811,6 @@
         if not self._cfg.interwikiname:
             return None
             
-        # Interwiki links must use _ e.g Wiki:Main_Page
-        pagename = pagename.replace(" ", "_")
         return "%s:%s" % (self._cfg.interwikiname, pagename)
 
     # -----------------------------------------------------------------
@@ -936,7 +933,7 @@
             else:
                 markup = pagename
         else:
-            markup = '%s:%s' % (wikiname, pagename.replace(" ","_")) 
+            markup = '%s:%s' % (wikiname, pagename) 
         return markup
 
     def mailAccountData(self, cleartext_passwd=None):
--- a/MoinMoin/userform.py	Sun Jun 11 11:04:38 2006 +0200
+++ b/MoinMoin/userform.py	Tue Jun 13 17:46:57 2006 +0200
@@ -38,10 +38,6 @@
 
         Each line is a page name, empty lines ignored.
 
-        Items can use '_' as spaces, needed by [name_with_spaces label]
-        format used in quicklinks. We do not touch those names here, the
-        underscores are handled later by the theme code.
-
         @param key: the form key to get
         @rtype: list of unicode strings
         @return: list of normalized names
@@ -53,10 +49,6 @@
             item = item.strip()
             if not item:
                 continue
-            # Normalize names - except [name_with_spaces label]
-            # Commented out to allow URLs
-            #if not (item.startswith('[') and item.endswith(']')):
-            #    item = self.request.normalizePagename(item)
             items.append(item)
         return items
 
@@ -408,7 +400,7 @@
         options = []
         users = user.getUserList(self.request)
         for uid in users:
-            name = user.User(self.request, id=uid).name # + '_' + uid # for debugging
+            name = user.User(self.request, id=uid).name # + '/' + uid # for debugging
             options.append((name, name))
         options.sort()
 
--- a/MoinMoin/wikiutil.py	Sun Jun 11 11:04:38 2006 +0200
+++ b/MoinMoin/wikiutil.py	Tue Jun 13 17:46:57 2006 +0200
@@ -208,7 +208,6 @@
     @rtype: string
     @return: the quoted filename, all unsafe characters encoded
     """
-    pagename = pagename.replace(u' ', u'_')
     pagename = pagename.encode(charset)
     return urllib.quote(pagename)
 
@@ -295,7 +294,6 @@
     @rtype: string
     @return: quoted name, safe for any file system
     """
-    wikiname = wikiname.replace(u' ', u'_') # " " -> "_"
     filename = wikiname.encode(charset)
     
     quoted = []    
@@ -376,7 +374,6 @@
     #    raise InvalidFileNameError(filename)
     
     wikiname = decodeUserInput(wikiname, charsets)
-    wikiname = wikiname.replace(u'_', u' ') # "_" -> " "
     return wikiname
 
 # time scaling
@@ -481,51 +478,8 @@
 #############################################################################
 ### InterWiki
 #############################################################################
-
-def split_wiki(wikiurl):
-    """
-    Split a wiki url.
-    
-    @param wikiurl: the url to split
-    @rtype: tuple
-    @return: (tag, tail)
-    """
-    # !!! use a regex here!
-    try:
-        wikitag, tail = wikiurl.split(":", 1)
-    except ValueError:
-        try:
-            wikitag, tail = wikiurl.split("/", 1)
-        except ValueError:
-            wikitag, tail = 'Self', wikiurl
-    return wikitag, tail
-
-
-def join_wiki(wikiurl, wikitail):
-    """
-    Add a page name to an interwiki url.
-    
-    @param wikiurl: wiki url, maybe including a $PAGE placeholder
-    @param wikitail: page name
-    @rtype: string
-    @return: generated URL of the page in the other wiki
-    """
-    if wikiurl.find('$PAGE') == -1:
-        return wikiurl + wikitail
-    else:
-        return wikiurl.replace('$PAGE', wikitail)
-
-
-def resolve_wiki(request, wikiurl):
-    """
-    Resolve an interwiki link.
-    
-    @param request: the request object
-    @param wikiurl: the InterWiki:PageName link
-    @rtype: tuple
-    @return: (wikitag, wikiurl, wikitail, err)
-    """
-    # load map (once, and only on demand)
+def load_wikimap(request):
+    """ load interwiki map (once, and only on demand) """
     try:
         _interwiki_list = request.cfg._interwiki_list
     except AttributeError:
@@ -565,15 +519,75 @@
 
         # save for later
         request.cfg._interwiki_list = _interwiki_list
-
-    # split wiki url
-    wikitag, tail = split_wiki(wikiurl)
+    
+    return _interwiki_list
+    
+def split_wiki(wikiurl):
+    """ Split a wiki url, e.g:
+    
+    'MoinMoin:FrontPage' -> "MoinMoin", "FrontPage", ""
+    'FrontPage' -> "Self", "FrontPage", ""
+    'MoinMoin:"Page with blanks" link title' -> "MoinMoin", "Page with blanks", "link title"
 
-    # return resolved url
-    if _interwiki_list.has_key(wikitag):
-        return (wikitag, _interwiki_list[wikitag], tail, False)
+    can also be used for:
+
+    'attachment:"filename with blanks.txt" other title' -> "attachment", "filename with blanks.txt", "other title"
+
+    @param wikiurl: the url to split
+    @rtype: tuple
+    @return: (wikiname, pagename, linktext)
+    """
+    try:
+        wikiname, rest = wikiurl.split(":", 1) # e.g. MoinMoin:FrontPage
+    except ValueError:
+        try:
+            wikiname, rest = wikiurl.split("/", 1) # for what is this used?
+        except ValueError:
+            wikiname, rest = 'Self', wikiurl
+    first_char = rest[0]
+    if first_char in "'\"": # quoted pagename
+        pagename_linktext = rest[1:].split(first_char, 1)
+    else: # not quoted, split on whitespace
+        pagename_linktext = rest.split(None, 1)
+    if len(pagename_linktext) == 1:
+        pagename, linktext = pagename_linktext[0], ""
     else:
-        return (wikitag, request.getScriptname(), "/InterWiki", True)
+        pagename, linktext = pagename_linktext
+    linktext = linktext.strip()
+    return wikiname, pagename, linktext
+
+def resolve_wiki(request, wikiurl):
+    """ Resolve an interwiki link.
+    
+    @param request: the request object
+    @param wikiurl: the InterWiki:PageName link
+    @rtype: tuple
+    @return: (wikitag, wikiurl, wikitail, err)
+    """
+    _interwiki_list = load_wikimap(request)
+    wikiname, pagename, linktext = split_wiki(wikiurl)
+    if _interwiki_list.has_key(wikiname):
+        return (wikiname, _interwiki_list[wikiname], pagename, False)
+    else:
+        return (wikiname, request.getScriptname(), "/InterWiki", True)
+
+def join_wiki(wikiurl, wikitail):
+    """
+    Add a (url_quoted) page name to an interwiki url.
+   
+    Note: We can't know what kind of URL quoting a remote wiki expects.
+          We just use a utf-8 encoded string with standard URL quoting.
+          
+    @param wikiurl: wiki url, maybe including a $PAGE placeholder
+    @param wikitail: page name
+    @rtype: string
+    @return: generated URL of the page in the other wiki
+    """
+    wikitail = url_quote(wikitail)
+    if '$PAGE' in wikiurl:
+        return wikiurl.replace('$PAGE', wikitail)
+    else:
+        return wikiurl + wikitail
 
 
 #############################################################################
--- a/docs/CHANGES	Sun Jun 11 11:04:38 2006 +0200
+++ b/docs/CHANGES	Tue Jun 13 17:46:57 2006 +0200
@@ -107,8 +107,21 @@
       'item', it will use a cache directory per item (== per page).
       Creating a CacheEntry without explicit scope is DEPRECATED.
     * smileys moved from MoinMoin.config to MoinMoin.theme
+    * removed all _ magic in URLs and filenames
+      TODO: write mig script for data_dir
+      TODO: make blanks in interwiki pagelinks possible
 
   New Features:
+    * Removed "underscore in URL" == "blank in pagename magic" - it made more
+      trouble than it was worth. If you still want to have a _ in URL, just
+      put a _ into pagename.
+    * Introduced quoting for pagenames and new, easier link markup:
+      * ["Page with blanks" but different link text],
+        NOTE: using [:Page with blanks:but different link text] is DEPRECATED.
+      * ["/Sub Page" with different link text]
+      * MoinMoin:"Page with blanks"
+      * [wiki:MoinMoin:"Page with blanks" different link text]
+      * attachment:"blanks are evil.txt"
 
     * FeatureRequests/WikiEmailIntegration TODO:make some help page when stable
     * HTML parser (called "html") that allows you to use HTML on the page.