Index: /Users/eblot/Sources/Svn/edgewall.org/trac/trunk/trac/versioncontrol/svn_fs.py
===================================================================
--- /Users/eblot/Sources/Svn/edgewall.org/trac/trunk/trac/versioncontrol/svn_fs.py	(revision 8199)
+++ /Users/eblot/Sources/Svn/edgewall.org/trac/trunk/trac/versioncontrol/svn_fs.py	(working copy)
@@ -321,13 +322,13 @@
     
     def render_property(self, name, mode, context, props):
         if name == 'svn:externals':
-            return self._render_externals(props[name])
+            return self._render_externals(props[name], context)
         elif name == 'svn:mergeinfo' or name.startswith('svnmerge-'):
             return self._render_mergeinfo(props[name])
 
-    def _render_externals(self, prop):
+    def _render_externals(self, prop, context):
         if not self._externals_map:
             for dummykey, value in self.config.options('svn:externals'):
                 value = value.split()
@@ -340,28 +341,68 @@
                 self._externals_map[key] = value.replace('%', '%%') \
                                            .replace('$path', '%(path)s') \
                                            .replace('$rev', '%(rev)s')
-        externals = []
+        externals_data = []
+        def add_externals_url(localpath, url, rev, href): 
+            externals_data.append(((localpath, url or '', rev or ''), href))
         for external in prop.splitlines():
             elements = external.split()
             if not elements:
                 continue
-            localpath, rev, url = elements[0], '', elements[-1]
-            if localpath.startswith('#'):
-                externals.append((external, None, None, None, None))
-                continue
-            if len(elements) == 3:
-                rev = elements[1]
-                rev = rev.replace('-r', '')
+            if elements[-1].find(u'://') != -1:
+                # old-style externals syntax
+                localpath, rev, url = elements[0], '', elements[-1]
+                if localpath.startswith('#'):
+                    externals_data.append((external, None, None))
+                    continue
+                if len(elements) > 2:
+                    rev = elements[len(elements)==4 and 3 or 2]
+                    rev = rev.replace('-r', '')
+            elif len(elements) > 1:
+                # new-style externals syntax
+                resource = context.resource
+                localpath = resource.id
+                url, localpath = elements[-2], elements[-1]
+                if len(elements) > 2:
+                    rev = elements[len(elements)==4 and 1 or 0]
+                    rev = rev.replace('-r', '')
+                else:
+                    rev = ''
+                    if '@' in url:
+                        (url, rev) = url.split('@') 
+                if url.startswith(u'^/'):
+                    # relative to repository root
+                    href = context.req.href.browser(url[1:], rev=rev)
+                    add_externals_url(localpath, url[1:], rev, href)
+                    continue
+                elif url.startswith(u'../'):
+                    # relative to the directory
+                    remotepath = localpath
+                    while url.startswith(u'../'):
+                        url = url[3:]
+                        (remotepath, child) = posixpath.split(remotepath)
+                    remotepath = posixpath.join('/'+remotepath, url)
+                    href = context.req.href.browser(url, rev=rev)
+                    add_externals_url(localpath, remotepath, rev, href)
+                    continue
+                elif url.startswith(u'/'):
+                    # relative to server root or to scheme
+                    while url.startswith(u'//'):
+                        # relative to scheme, handle as server root
+                        url = url[1:] 
+                    # relative to server root
             # retrieve a matching entry in the externals map
             prefix = []
             base_url = url
             while base_url:
                 if base_url in self._externals_map or base_url==u'/':
                     break
+                if base_url.endswith(':'):
+                    prefix.append(base_url+'//')
+                    base_url = ''
+                    break
                 base_url, pref = posixpath.split(base_url)
                 prefix.append(pref)
             href = self._externals_map.get(base_url)
-            revstr = rev and ' at revision '+rev or ''
             if not href and (url.startswith('http://') or 
                              url.startswith('https://')):
                 href = url.replace('%', '%%')
@@ -369,37 +410,185 @@
                 remotepath = ''
                 if prefix:
                     remotepath = posixpath.join(*reversed(prefix))
-                externals.append((localpath, revstr, base_url, remotepath,
-                                  href % {'path': remotepath, 'rev': rev}))
+                add_externals_url(localpath, url, rev,
+                                  href % {'path': remotepath, 'rev': rev})
             else:
-                externals.append((localpath, revstr, url, None, None))
-        externals_data = []
-        for localpath, rev, url, remotepath, href in externals:
-            label = localpath
-            if url is None:
-                title = ''
-            elif href:
-                if url:
-                    url = ' in ' + url
-                label += rev + url
-                title = ''.join((remotepath, rev, url))
+                add_externals_url(localpath, url, rev, None)
+        trs = []
+        for label, href in externals_data:
+            if not href:
+                tr = tag.tr(tag.td(label[0]),
+                            tag.td(tag.a(label[1], title=\
+                                _('No svn:externals configured in trac.ini')),
+                            tag.td(label[2])))
             else:
-                title = _('No svn:externals configured in trac.ini')
-            externals_data.append((label, href, title))
-        return tag.ul([tag.li(tag.a(label, href=href, title=title))
-                       for label, href, title in externals_data])
+                tr = tag.tr(tag.td(label[0]),
+                            tag.td(tag.a(label[1], href=href), title=\
+                                _('Jump to external')),
+                            tag.td(tag.a(label[2], href=href)))
+            trs.append(tr)
+        return tag.table(tag.tbody(trs))

