Index: wiki-default/InterTrac
===================================================================
--- wiki-default/InterTrac	(.../trunk)	(revision 0)
+++ wiki-default/InterTrac	(.../branches/cboos-dev/intertrac-branch)	(revision 2496)
@@ -0,0 +1,108 @@
+= InterTrac Extension for TracLinks =
+
+''This is a proposal for implementing #234''.
+''It's candidate for integration in the trunk, after the 0.9 release (see #2041)''
+
+== Definitions ==
+
+An InterTrac link is used for referring to a Trac object 
+(Wiki page, changeset, ticket, ...) located in another
+Trac environment.
+
+== Link Syntax ==
+
+{{{
+<target_environment>:<TracLinks>
+}}}
+
+The link is composed by the target environment name, 
+followed by a colon (e.g. `trac:`),
+followed by a regular TracLinks, of any flavor.
+
+That target environment name is either the real name of the 
+environment, or an alias for it. 
+The aliases are defined in `trac.ini` (see below).
+The prefix is case insensitive.
+
+For convenience, there's also an alternative short-hand form, 
+where one can use an alias as an immediate prefix 
+for the identifier of a ticket, changeset or report:
+(e.g. `#T234`, `[T1508]`, `[trac 1508]`, ...)
+
+== Examples ==
+
+Besides the other environments run by the same server process
+(called ''sibling'' environments), which are automatically detected,
+(''Note: currently only in `tracd`''),
+it is necessary to setup a configuration for the InterTrac facility:
+ * in order to refer to a remote Trac
+ * for defining environment aliases
+
+This is done quite simply in an `[intertrac]` section
+within the `trac.ini` file.
+
+Example configuration:
+{{{
+...
+[intertrac]
+## -- Example of setting up an alias:
+t = trac
+
+## -- Link to an external Trac:
+trac.title = Edgewall's Trac for Trac
+trac.url = http://projects.edgewall.com/trac
+
+#trac.svn = http://repos.edgewall.com/projects/trac 
+# Hint: .svn information could be used in the future to support svn:externals...
+}}}
+
+Now, given this configuration, one could create the following links:
+ * to the current InterTrac page:
+   * `trac:wiki:InterTrac` ->
+     [http://projects.edgewall.com/trac/wiki/InterTrac trac:wiki:InterTrac]
+   * `t:wiki:InterTrac` ->
+     [http://projects.edgewall.com/trac/wiki/InterTrac t:wiki:InterTrac]
+   * Keys are case insensitive: `T:wiki:InterTrac` -> 
+     [http://projects.edgewall.com/trac/wiki/InterTrac T:wiki:InterTrac]
+ * to the ticket #234:
+   * `trac:ticket:234` ->
+     [http://projects.edgewall.com/trac/ticket/234 trac:ticket:234]
+   * `trac:#234` ->
+     [http://projects.edgewall.com/trac/ticket/234 trac:#234]
+   * `#T234` ->
+     [http://projects.edgewall.com/trac/search?q=#234 #T234]
+ * to the changeset [1912]:
+   * `trac:changeset:1912` ->
+     [http://projects.edgewall.com/trac/changeset/1912 trac:changeset:1912]
+   * `trac:[1912]` ->
+     [http:"//projects.edgewall.com/trac/search?q=[1912]" "trac:[1912]"]
+   * `[T1912]` ->
+     [http://projects.edgewall.com/trac/changeset/1912 "[T1912]"]
+
+Anything not given as explicit links (intertrac_prefix:module:id)
+is interpreted by the remote Trac, relying on its quickjump
+facility.
+
+
+
+See also: TracLinks, InterWiki
+
+----
+== Implementation Notes ==
+
+Currently, the `[intertrac]` configuration has to be repeated 
+for each Trac environment, but there's work in progress concerning a 
+[ticket:1051 centralized trac.ini], which would help greatly here.
+
+This idea was first proposed as a patch for #234, and 
+has been implemented in the following branch: 
+source:branches/cboos-dev/intertrac-branch
+
+The general idea is that any `[a-zA-Z.+-]+:` prefix, 
+followed by anything which is not a space, has to be interpreted as:
+ 1. maybe an alias to something else; if yes, it is dereferenced
+    before going on
+ 1. then, it's maybe a link prefix given by an `IWikiSyntaxProvider` component 
+ 1. if not, it's maybe an environment name (!InterTrac link)
+ 1. if not, it's maybe an !InterWiki link
+ 1. if not, it is not a link

Property changes on: wiki-default\InterTrac
___________________________________________________________________
Name: svn:mime-type
   + text/x-trac-wiki

Index: wiki-default/InterMapTxt
===================================================================
--- wiki-default/InterMapTxt	(.../trunk)	(revision 0)
+++ wiki-default/InterMapTxt	(.../branches/cboos-dev/intertrac-branch)	(revision 2496)
@@ -0,0 +1,63 @@
+= InterMapTxt =
+== This is the place for defining InterWiki prefixes ==
+
+This page was modelled after the MeatBall:InterMapTxt page.
+In addition, an optional comment is allowed after the mapping.
+
+
+This page is interpreted in a special way by Trac, in order to support
+!InterWiki links in a flexible and dynamic way.
+
+The code block after the first line separator in this page
+will be interpreted as a list of !InterWiki specifications:
+{{{
+prefix <space> URL [<space> # comment]
+}}}
+
+By using `$1`, `$2`, etc. within the URL, it is possible to create 
+InterWiki links which support multiple arguments, e.g. Trac:ticket:40.
+The URL itself can be optionally followed by a comment, 
+which will subsequently be used for decorating the links 
+using that prefix.
+
+New !InterWiki links can be created by adding to that list, in real time.
+Note however that ''deletions'' are also taken into account immediately,
+so it may be better to use comments for disabling prefixes.
+
+Also note that !InterWiki prefixes are case insensitive.
+
+
+== List of Active Prefixes ==
+
+[[InterWiki]]
+
+----
+
+== Prefix Definitions ==
+
+{{{
+PEP     http://www.python.org/peps/pep-$1.html                                       # Python Enhancement Proposal 
+TracML  http://thread.gmane.org/gmane.comp.version-control.subversion.trac.general/  # Trac Mailing List
+
+#
+# A arbitrary pick of InterWiki prefixes...
+#
+Acronym          http://www.acronymfinder.com/af-query.asp?String=exact&Acronym=
+C2find           http://c2.com/cgi/wiki?FindPage&value=
+Cache            http://www.google.com/search?q=cache:
+CPAN             http://search.cpan.org/perldoc?
+DebianBug        http://bugs.debian.org/
+DebianPackage    http://packages.debian.org/
+Dictionary       http://www.dict.org/bin/Dict?Database=*&Form=Dict1&Strategy=*&Query=
+Google           http://www.google.com/search?q=
+GoogleGroups     http://groups.google.com/groups?q=
+JargonFile       http://downlode.org/perl/jargon-redirect.cgi?term=
+MeatBall         http://www.usemod.com/cgi-bin/mb.pl?
+MetaWiki         http://sunir.org/apps/meta.pl?
+MetaWikiPedia    http://meta.wikipedia.org/wiki/
+MoinMoin         http://moinmoin.wikiwikiweb.de/
+WhoIs            http://www.whois.sc/
+Why              http://clublet.com/c/c/why?
+Wiki             http://c2.com/cgi/wiki?
+WikiPedia        http://en.wikipedia.org/wiki/
+}}}

Property changes on: wiki-default\InterMapTxt
___________________________________________________________________
Name: svn:mime-type
   + text/x-trac-wiki

Index: wiki-default/WikiStart
===================================================================
--- wiki-default/WikiStart	(.../trunk)	(revision 2438)
+++ wiki-default/WikiStart	(.../branches/cboos-dev/intertrac-branch)	(revision 2496)
@@ -1,4 +1,4 @@
-= Welcome to Trac 0.9 =
+= Welcome to Trac 0.9-intertrac =
 
 Trac is a '''minimalistic''' approach to '''web-based''' management of
 '''software projects'''. Its goal is to simplify effective tracking and handling of software issues, enhancements and overall progress.
Index: wiki-default/InterWiki
===================================================================
--- wiki-default/InterWiki	(.../trunk)	(revision 0)
+++ wiki-default/InterWiki	(.../branches/cboos-dev/intertrac-branch)	(revision 2496)
@@ -0,0 +1,68 @@
+= Support for InterWiki links =
+
+''This is a proposal for implementing #40 and #1414''
+''It's candidate for integration in the trunk, after the 0.9 release (see #2041)''
+
+== Definition ==
+
+An InterWiki link can be used for referring to a Wiki page
+located in another Wiki system, and by extension, to any object
+located in any other Web application, provided a simple URL 
+mapping can be done.
+
+== Link Syntax ==
+
+{{{
+<target_wiki>(:<identifier>)+
+}}}
+
+The link is composed by the targeted Wiki (or system) name,
+followed by a column (e.g. {{{MeatBall:}}}),
+followed by a page specification in the target.
+Note that, as for InterTrac prefixes, InterWiki prefixes are case insensitive.
+
+The target Wiki URL is looked up in a the InterMapTxt wiki page, 
+modelled after
+[http://www.usemod.com/cgi-bin/mb.pl?InterMapTxt MeatBall:InterMapTxt].
+
+An addition to traditional InterWiki links, where the target
+is simply ''appended'' to the URL, 
+Trac supports parametric InterWiki URLs:
+identifiers `$1`, `$2`, ... in the URL
+will be replaced by corresponding arguments from a list
+made up from the page specification split by the ":" token.
+
+== Examples ==
+
+If the following is an excerpt of the InterMapTxt page:
+
+{{{
+= InterMapTxt =
+== This is the place for defining InterWiki prefixes ==
+
+Currently active prefixes: [[InterWiki]]
+
+This page is modelled after the MeatBall:InterMapTxt page.
+In addition, an optional comment is allowed after the mapping.
+----
+{{{
+PEP     http://www.python.org/peps/pep-$1.html                                       # Python Enhancement Proposal 
+TracML  http://thread.gmane.org/gmane.comp.version-control.subversion.trac.general/  # Trac Mailing List
+
+...
+MeatBall http://www.usemod.com/cgi-bin/mb.pl?
+MetaWiki http://sunir.org/apps/meta.pl?
+MetaWikiPedia http://meta.wikipedia.org/wiki/
+MoinMoin http://moinmoin.wikiwikiweb.de/
+...
+}}}
+}}}
+
+Then, 
+ * `MoinMoin:InterWikiMap` should be rendered as 
+   [http://moinmoin.wikiwikiweb.de/InterWikiMap MoinMoin:InterWikiMap]
+   and the ''title'' for that link would be "!InterWikiMap in !MoinMoin"
+ * {{{TracML:4346}}} should be rendered as 
+   [http://thread.gmane.org/gmane.comp.version-control.subversion.trac.general/4346 TracML:4346]
+   and the ''title'' for that link would be "4346 in Trac Mailing List"
+   (idea: I should allow positional parameters in the comment as well)

Property changes on: wiki-default\InterWiki
___________________________________________________________________
Name: svn:mime-type
   + text/x-trac-wiki

Index: trac/env.py
===================================================================
--- trac/env.py	(.../trunk)	(revision 2438)
+++ trac/env.py	(.../branches/cboos-dev/intertrac-branch)	(revision 2496)
@@ -74,6 +74,7 @@
         ComponentManager.__init__(self)
 
         self.path = path
+        self.siblings = {}
         self.__cnx_pool = None
         if create:
             self.create(db_str)
Index: trac/ticket/api.py
===================================================================
--- trac/ticket/api.py	(.../trunk)	(revision 2438)
+++ trac/ticket/api.py	(.../branches/cboos-dev/intertrac-branch)	(revision 2496)
@@ -19,7 +19,7 @@
 from trac import util
 from trac.core import *
 from trac.perm import IPermissionRequestor
-from trac.wiki import IWikiSyntaxProvider
+from trac.wiki import IWikiSyntaxProvider, Formatter
 from trac.Search import ISearchSource, query_to_sql, shorten_result
 
 
@@ -140,10 +140,14 @@
                 ('ticket', self._format_link)]
 
     def get_wiki_syntax(self):
-        yield (r"!?#\d+",
-               lambda x, y, z: self._format_link(x, 'ticket', y[1:], y))
+        yield (r"!?#(?P<it_ticket>%s)?\d+" % Formatter.INTERTRAC_SCHEME,
+               lambda x, y, z: self._format_link(x, 'ticket', y[1:], y, z))
 
-    def _format_link(self, formatter, ns, target, label):
+    def _format_link(self, formatter, ns, target, label, fullmatch=None):
+        intertrac = formatter.shorthand_intertrac_helper(ns, target, label,
+                                                         fullmatch)
+        if intertrac:
+            return intertrac
         cursor = formatter.db.cursor()
         cursor.execute("SELECT summary,status FROM ticket WHERE id=%s",
                        (target,))
Index: trac/ticket/report.py
===================================================================
--- trac/ticket/report.py	(.../trunk)	(revision 2438)
+++ trac/ticket/report.py	(.../branches/cboos-dev/intertrac-branch)	(revision 2496)
@@ -24,7 +24,7 @@
 from trac.perm import IPermissionRequestor
 from trac.web import IRequestHandler
 from trac.web.chrome import add_link, add_stylesheet, INavigationContributor
-from trac.wiki import wiki_to_html, IWikiSyntaxProvider
+from trac.wiki import wiki_to_html, IWikiSyntaxProvider, Formatter
 
 
 dynvars_re = re.compile('\$([A-Z]+)')
@@ -510,9 +510,14 @@
         yield ('report', self._format_link)
 
     def get_wiki_syntax(self):
-        yield (r"!?\{\d+\}", lambda x, y, z: self._format_link(x, 'report', y[1:-1], y))
+        yield (r"!?\{(?P<it_report>%s\s*)?\d+\}" % Formatter.INTERTRAC_SCHEME,
+               lambda x, y, z: self._format_link(x, 'report', y[1:-1], y, z))
 
-    def _format_link(self, formatter, ns, target, label):
+    def _format_link(self, formatter, ns, target, label, fullmatch=None):
+        intertrac = formatter.shorthand_intertrac_helper(ns, target, label,
+                                                         fullmatch)
+        if intertrac:
+            return intertrac
         report, args = target, ''
         if '?' in target:
             report, args = target.split('?')
Index: trac/__init__.py
===================================================================
--- trac/__init__.py	(.../trunk)	(revision 2438)
+++ trac/__init__.py	(.../branches/cboos-dev/intertrac-branch)	(revision 2496)
@@ -10,7 +10,7 @@
 """
 __docformat__ = 'epytext en'
 
-__version__ = '0.9'
+__version__ = '0.9-intertrac'
 __url__ = 'http://trac.edgewall.com/'
 __copyright__ = '(C) 2003-2005 Edgewall Software'
 __license__ = 'BSD'
Index: trac/versioncontrol/web_ui/changeset.py
===================================================================
--- trac/versioncontrol/web_ui/changeset.py	(.../trunk)	(revision 2438)
+++ trac/versioncontrol/web_ui/changeset.py	(.../branches/cboos-dev/intertrac-branch)	(revision 2496)
@@ -30,7 +30,8 @@
 from trac.versioncontrol.diff import get_diff_options, hdf_diff, unified_diff
 from trac.web import IRequestHandler
 from trac.web.chrome import add_link, add_stylesheet, INavigationContributor
-from trac.wiki import wiki_to_html, wiki_to_oneliner, IWikiSyntaxProvider
+from trac.wiki import wiki_to_html, wiki_to_oneliner, IWikiSyntaxProvider, \
+                      Formatter
 
 
 class ChangesetModule(Component):
@@ -354,15 +355,21 @@
     # IWikiSyntaxProvider methods
     
     def get_wiki_syntax(self):
-        yield (r"!?\[\d+\]|(?:\b|!)r\d+\b(?!:\d)",
+        yield (r"!?\[(?P<it_changeset>%s\s*)?\d+\]|" \
+               % Formatter.INTERTRAC_SCHEME +           # [1], [T1] or [trac 1]
+               r"(?:\b|!)r\d+\b(?!:\d)",                # r1 but not r1:2
                lambda x, y, z: self._format_link(x, 'changeset',
                                                  y[0] == 'r' and y[1:]
-                                                 or y[1:-1], y))
+                                                 or y[1:-1], y, z))
 
     def get_link_resolvers(self):
         yield ('changeset', self._format_link)
 
-    def _format_link(self, formatter, ns, rev, label):
+    def _format_link(self, formatter, ns, rev, label, fullmatch=None):
+        intertrac = formatter.shorthand_intertrac_helper(ns, rev, label,
+                                                         fullmatch)
+        if intertrac:
+            return intertrac
         cursor = formatter.db.cursor()
         cursor.execute('SELECT message FROM revision WHERE rev=%s', (rev,))
         row = cursor.fetchone()
Index: trac/wiki/api.py
===================================================================
--- trac/wiki/api.py	(.../trunk)	(revision 2438)
+++ trac/wiki/api.py	(.../branches/cboos-dev/intertrac-branch)	(revision 2496)
@@ -214,3 +214,4 @@
         else:
             return '<a class="wiki" href="%s">%s</a>' \
                    % (formatter.href.wiki(page) + anchor, label)
+
Index: trac/wiki/tests/wiki-tests.txt
===================================================================
--- trac/wiki/tests/wiki-tests.txt	(.../trunk)	(revision 2438)
+++ trac/wiki/tests/wiki-tests.txt	(.../branches/cboos-dev/intertrac-branch)	(revision 2496)
@@ -51,9 +51,11 @@
 <a class="ext-link" href="http://www.edgewall.com/"><span class="icon"></span>http://www.edgewall.com/</a>
 ==============================
 #1, [1], r1, {1}
+#12, [12], r12, {12}
 ------------------------------
 <p>
 <a class="missing ticket" href="/ticket/1" rel="nofollow">#1</a>, <a class="missing changeset" href="/changeset/1" rel="nofollow">[1]</a>, <a class="missing changeset" href="/changeset/1" rel="nofollow">r1</a>, <a class="report" href="/report/1">{1}</a>
+<a class="missing ticket" href="/ticket/12" rel="nofollow">#12</a>, <a class="missing changeset" href="/changeset/12" rel="nofollow">[12]</a>, <a class="missing changeset" href="/changeset/12" rel="nofollow">r12</a>, <a class="report" href="/report/12">{12}</a>
 </p>
 ------------------------------
 ==============================
@@ -137,10 +139,10 @@
 </p>
 ------------------------------
 ==============================
-CamelCase,CamelCase.CamelCase:CamelCase
+CamelCase,CamelCase.CamelCase: CamelCase
 ------------------------------
 <p>
-<a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>,<a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>.CamelCase:CamelCase
+<a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>,<a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>.<a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>: <a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>
 </p>
 ------------------------------
 ==============================
@@ -855,3 +857,78 @@
 ------------------------------
 || a || 
 || b ||
+==============================
+t:wiki:InterTrac
+trac:wiki:InterTrac
+[t:wiki:InterTrac intertrac]
+[trac:wiki:InterTrac intertrac]
+------------------------------
+<p>
+<a class="ext-link" href="http://projects.edgewall.com/trac/wiki/InterTrac" title="wiki:InterTrac in Trac's Trac"><span class="icon"></span>t:wiki:InterTrac</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/wiki/InterTrac" title="wiki:InterTrac in Trac's Trac"><span class="icon"></span>trac:wiki:InterTrac</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/wiki/InterTrac" title="wiki:InterTrac in Trac's Trac"><span class="icon"></span>intertrac</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/wiki/InterTrac" title="wiki:InterTrac in Trac's Trac"><span class="icon"></span>intertrac</a>
+</p>
+------------------------------
+==============================
+trac:ticket:2041
+[trac:ticket:2041 Trac #2041]
+#T2041
+#trac2041
+------------------------------
+<p>
+<a class="ext-link" href="http://projects.edgewall.com/trac/ticket/2041" title="ticket:2041 in Trac's Trac"><span class="icon"></span>trac:ticket:2041</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/ticket/2041" title="ticket:2041 in Trac's Trac"><span class="icon"></span>Trac #2041</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/ticket/2041" title="ticket:2041 in Trac's Trac"><span class="icon"></span>#T2041</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/ticket/2041" title="ticket:2041 in Trac's Trac"><span class="icon"></span>#trac2041</a>
+</p>
+------------------------------
+==============================
+trac:changeset:2081
+[trac:changeset:2081 Trac r2081]
+[T2081]
+[trac2081]
+[trac 2081]
+------------------------------
+<p>
+<a class="ext-link" href="http://projects.edgewall.com/trac/changeset/2081" title="changeset:2081 in Trac's Trac"><span class="icon"></span>trac:changeset:2081</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/changeset/2081" title="changeset:2081 in Trac's Trac"><span class="icon"></span>Trac r2081</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/changeset/2081" title="changeset:2081 in Trac's Trac"><span class="icon"></span>[T2081]</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/changeset/2081" title="changeset:2081 in Trac's Trac"><span class="icon"></span>[trac2081]</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/changeset/2081" title="changeset:2081 in Trac's Trac"><span class="icon"></span>[trac 2081]</a>
+</p>
+------------------------------
+==============================
+trac:report:1
+[trac:report:1 Trac r1]
+{T1}
+{trac1}
+{trac 1}
+------------------------------
+<p>
+<a class="ext-link" href="http://projects.edgewall.com/trac/report/1" title="report:1 in Trac's Trac"><span class="icon"></span>trac:report:1</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/report/1" title="report:1 in Trac's Trac"><span class="icon"></span>Trac r1</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/report/1" title="report:1 in Trac's Trac"><span class="icon"></span>{T1}</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/report/1" title="report:1 in Trac's Trac"><span class="icon"></span>{trac1}</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/report/1" title="report:1 in Trac's Trac"><span class="icon"></span>{trac 1}</a>
+</p>
+------------------------------
+==============================
+t:InterTrac
+trac:InterTrac
+[t:InterTrac intertrac]
+[trac:InterTrac intertrac]
+T:r2081
+T:#2041
+trac:#2041
+------------------------------
+<p>
+<a class="ext-link" href="http://projects.edgewall.com/trac/search?q=InterTrac" title="InterTrac in Trac's Trac"><span class="icon"></span>t:InterTrac</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/search?q=InterTrac" title="InterTrac in Trac's Trac"><span class="icon"></span>trac:InterTrac</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/search?q=InterTrac" title="InterTrac in Trac's Trac"><span class="icon"></span>intertrac</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/search?q=InterTrac" title="InterTrac in Trac's Trac"><span class="icon"></span>intertrac</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/search?q=r2081" title="r2081 in Trac's Trac"><span class="icon"></span>T:r2081</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/search?q=%232041" title="#2041 in Trac's Trac"><span class="icon"></span>T:#2041</a>
+<a class="ext-link" href="http://projects.edgewall.com/trac/search?q=%232041" title="#2041 in Trac's Trac"><span class="icon"></span>trac:#2041</a>
+</p>
+------------------------------
Index: trac/wiki/tests/formatter.py
===================================================================
--- trac/wiki/tests/formatter.py	(.../trunk)	(revision 2438)
+++ trac/wiki/tests/formatter.py	(.../branches/cboos-dev/intertrac-branch)	(revision 2496)
@@ -55,8 +55,13 @@
                 self.config = Configuration(None)
                 self.href = Href('/')
                 self.abs_href = Href('http://www.example.com/')
-                self._wiki_pages = {}
                 self.path = ''
+                # -- intertrac support
+                self.siblings = {}
+                self.config.set('intertrac', 'trac.title', "Trac's Trac")
+                self.config.set('intertrac', 'trac.url',
+                                "http://projects.edgewall.com/trac")
+                self.config.set('intertrac', 't', 'trac')
             def component_activated(self, component):
                 component.env = self
                 component.config = self.config
Index: trac/wiki/formatter.py
===================================================================
--- trac/wiki/formatter.py	(.../trunk)	(revision 2438)
+++ trac/wiki/formatter.py	(.../branches/cboos-dev/intertrac-branch)	(revision 2496)
@@ -27,10 +27,11 @@
     from StringIO import StringIO
 
 from trac import util
+from trac.core import *
 from trac.mimeview import *
-from trac.wiki.api import WikiSystem
+from trac.wiki.api import WikiSystem, IWikiChangeListener, IWikiMacroProvider
 
-__all__ = ['wiki_to_html', 'wiki_to_oneliner', 'wiki_to_outline']
+__all__ = ['wiki_to_html', 'wiki_to_oneliner', 'wiki_to_outline', 'Formatter' ]
 
 
 def system_message(msg, text):
@@ -134,6 +135,7 @@
     INLINE_TOKEN = "`"
 
     LINK_SCHEME = r"[\w.+-]+" # as per RFC 2396
+    INTERTRAC_SCHEME = r"[a-zA-Z.+-]+?" # no digits (support for shorthand links)
 
     QUOTED_STRING = r"'[^']+'|\"[^\"]+\""
 
@@ -296,13 +298,67 @@
             return self._make_link(ns, target, match, label)
 
     def _make_link(self, ns, target, match, label):
+        # check first for an alias defined in trac.ini
+        ns = self.env.config.get('intertrac', ns.upper(), ns)
         if ns in self.link_resolvers:
             return self.link_resolvers[ns](self, ns, target, label)
         elif target.startswith('//') or ns == "mailto":
             return self._make_ext_link(ns+':'+target, label)
         else:
-            return match
+            intertrac = self._make_intertrac_link(ns, target, label)
+            if intertrac:
+                return intertrac
+            else:
+                interwiki = self._make_interwiki_link(ns, target, label)
+                if interwiki:
+                    return interwiki
+                else:
+                    return match
 
+    def _make_intertrac_link(self, ns, target, label):
+        if self.env.siblings.has_key(ns):
+            sibling = self.env.siblings[ns]
+            if not hasattr(sibling, 'href'):
+                from trac.web.href import Href
+                def xchg_base(base):
+                    return '/'.join(base.split('/')[:-1] + [ns])
+                sibling.href = Href(xchg_base(self.env.href.base))
+                sibling.abs_href = Href(xchg_base(self.env.abs_href.base))
+            ref = wiki_to_oneliner(target, sibling)
+            return ref.replace('>%s' % target, '>%s' % label)
+        url = self.env.config.get('intertrac', ns.upper()+'.url')
+        if url:
+            name = self.env.config.get('intertrac', ns.upper()+'.title',
+                                       'Trac project %s' % ns)
+            sep = target.find(':')
+            if sep != -1:
+                url = '%s/%s/%s' % (url, target[:sep], target[sep+1:])
+            else: 
+                url = '%s/search?q=%s' % (url, urllib.quote_plus(target))
+            return self._make_ext_link(url, label, '%s in %s' % (target, name))
+        else:
+            return None
+
+    def shorthand_intertrac_helper(self, ns, target, label, fullmatch):
+        if fullmatch: # short form
+            it_grp = fullmatch.group('it_%s' % ns)
+            if it_grp:
+                alias = it_grp.strip()
+                intertrac = self.env.config.get('intertrac', alias.upper(),
+                                                alias)
+                target = '%s:%s' % (ns, target[len(it_grp):])
+                it = self._make_intertrac_link(intertrac, target, label)
+                return it or label
+        return None
+
+    def _make_interwiki_link(self, ns, target, label):
+        interwiki = InterWikiMap(self.env)
+        if interwiki.has_key(ns):
+            url, title = interwiki.url(ns, target)
+            return self._make_ext_link(url, label, '%s in %s' % (target, title))
+        else:
+            return None
+
     def _make_ext_link(self, url, text, title=''):
         title_attr = title and ' title="%s"' % title or ''
         if Formatter.img_re.search(url) and self.flavor != 'oneliner':
@@ -762,3 +818,98 @@
     OutlineFormatter(env, absurls, db).format(wikitext, out, max_depth,
                                               min_depth)
     return out.getvalue()
+
+
+# -- InterWiki support
+
+class InterWikiMap(Component):
+
+    implements(IWikiChangeListener, IWikiMacroProvider)
+
+    _page_name = 'InterMapTxt'
+    _interwiki_re = re.compile(r"(\w+)[ \t]+([^ \t]+)(?:[ \t]+#(.*))?",
+                               re.UNICODE)
+    _argspec_re = re.compile(r"\$\d")
+
+    def __init__(self):
+        self._interwiki_map = None
+        # This dictionary maps upper-cased namespaces
+        # to (namespace, prefix, title) values
+
+    def has_key(self, ns):
+        if not self._interwiki_map:
+            self._update()
+        return self._interwiki_map.has_key(ns.upper())
+
+    def url(self, ns, target):
+        ns, url, title = self._interwiki_map[ns.upper()]
+        args = target.split(':')
+        def setarg(match):
+            num = int(match.group()[1:])
+            return 0 < num <= len(args) and args[num-1] or ''
+        url_with_args = re.sub(InterWikiMap._argspec_re, setarg, url)
+        if url_with_args == url: 
+            return url + target, title
+        else:
+            return url_with_args, title
+
+    # IWikiChangeListener methods
+
+    def wiki_page_added(self, page):
+        if page.name == InterWikiMap._page_name:
+            self._update()
+
+    def wiki_page_changed(self, page, version, t, comment, author, ipnr):
+        if page.name == InterWikiMap._page_name:
+            self._update()
+
+    def wiki_page_deleted(self, page):
+        if page.name == InterWikiMap._page_name:
+            self._interwiki_map.clear()
+
+    def _update(self):
+        from trac.wiki.model import WikiPage
+        self._interwiki_map = {}
+        content = WikiPage(self.env, InterWikiMap._page_name).text
+        in_map = False
+        for line in content.split('\n'):
+            if in_map:
+                if line.startswith('----'):
+                    in_map = False
+                else:
+                    m = re.match(InterWikiMap._interwiki_re, line)
+                    if m:
+                        prefix, url, title = m.groups()
+                        url = url.strip()
+                        title = title and title.strip() or prefix
+                        self._interwiki_map[prefix.upper()] = (prefix, url,
+                                                               title)
+            elif line.startswith('----'):
+                in_map = True
+
+    # IWikiMacroProvider
+
+    def get_macros(self):
+        yield 'InterWiki'
+
+    def get_macro_description(self, name): 
+        return "Provide a description list for the known InterWiki prefixes."
+
+    def render_macro(self, req, name, content):
+        if not self._interwiki_map:
+            self._update()
+        keys = self._interwiki_map.keys()
+        keys.sort()
+        buf = StringIO()
+        buf.write('<table><tr><th>Prefix</th><td>Site</td></tr>\n')
+        for k in keys:
+            prefix, url, title = self._interwiki_map[k]
+            shortened_url = url and url[:-1]
+            description = title == prefix and shortened_url or title
+            buf.write('<tr>\n' +
+                      ('<td><a href="%sRecentChanges">%s</a></td>'
+                       '<td><a href="%s">%s</a></td>\n') \
+                      % (url, prefix, shortened_url, description) +
+                      '</tr>\n')
+        buf.write('</table>\n')
+        return buf.getvalue()
Index: trac/web/standalone.py
===================================================================
--- trac/web/standalone.py	(.../trunk)	(revision 2438)
+++ trac/web/standalone.py	(.../branches/cboos-dev/intertrac-branch)	(revision 2496)
@@ -206,6 +206,7 @@
         self.auths = auths
 
         self.projects = {}
+        siblings = {}
         for env_path in env_paths:
             # Remove trailing slashes
             while env_path and not os.path.split(env_path)[1]:
@@ -217,13 +218,17 @@
                                     % (env_path, self.projects[project])
             else:
                 self.projects[project] = env_path
+            env = get_environment(None, self.get_env_opts(project))
+            siblings[project] = env
+        for p in siblings.values():
+            p.siblings = siblings
 
     def get_env_opts(self, project=None):
         if self.env_parent_dir:
             opts = self.env_parent_dir.items()
         else:
             opts = [('TRAC_ENV', self.projects[project])]
-        return dict(opts + os.environ.items())
+        return dict(os.environ.items() + opts) # TODO: backport
 
     def send_project_index(self, req):
         if self.env_parent_dir:

Property changes on: .
___________________________________________________________________
Name: svn:ignore
   - MANIFEST
dist
build

   + MANIFEST
dist
build
.hg
.hgignore


