Index: doxygentrac.py
===================================================================
--- doxygentrac.py	(revision 1398)
+++ doxygentrac.py	(working copy)
@@ -68,6 +68,9 @@
     encoding = Option('doxygen', 'encoding', 'iso-8859-1',
       """Default encoding used by the generated documentation files.""")
 
+    default_namespace = Option('doxygen', 'default_namespace', '',
+      """Default namespace to search for named objects in.""")
+
     SUMMARY_PAGES = """
     annotated classes dirs files functions globals hierarchy
     index inherits main namespaces namespacemembers
@@ -147,8 +150,8 @@
                 req.hdf['doxygen.wiki_page'] = wiki
                 return 'doxygen.cs', 'text/html'
             # use configured Doxygen index
-            path = os.path.join(self.base_path, self.default_doc,
-                                self.html_output, self.index)
+            req.redirect(os.path.join('trac', 'doxygen', self.default_doc,
+                                      self.html_output, self.index))
 
         # view 
         mimetype = mimetypes.guess_type(path)[0]
@@ -224,10 +227,15 @@
             if action == 'search':
                 return html.a(label, title=params, class_='missing',
                               href=formatter.href.doxygen())
+            if action == 'anchor':
+                # This is a hack!!! It ignore multiple projects/docsdirs, and it shouldn't
+                # create the HTML explicitly
+                return '<a href="%s/%s/%s" title="%s">%s</a>' % (formatter.href.base, "doxygen", link, params[1:], params[1:])
             else:
                 return html.a(label, title=params,
                               href=formatter.href.doxygen(link, path=path))
         yield ('doxygen', doxygen_link)
+        yield ('dox', doxygen_link)
 
     def get_wiki_syntax(self):
         return []
@@ -267,6 +275,44 @@
                                             path+" (not found)"))
             return existing_path, link
 
+        # do doxygen-style name->file mapping
+        # this is a little different than doxygen, but I don't see another
+        # way to make doxygen:Type<bool> links work, as it inserts a ' ' (or
+        # '_01') after/before the type name.
+
+        doxygen_file_map = { '_':'__', ':':'_1', '/':'_2', '<':'_3_01', '>':'_01_4', \
+                             '*':'_5', '&':'_6', '|':'_7', '.':'_8', '!':'_9', \
+                             ',':'_00',' ':'_01' }
+
+        re_name_map = { '+':'\\+', '*':'\\*', '(':'\\(', ')':'\\)', '[':'\\[', ']':'\\]', ' ':'' }
+
+        space_map = {' ':'' }
+
+        def map_string(str, map):
+            if str == None:
+                return None
+            mangledstring = ''
+            for i in str:
+                if i in map.keys():
+                    mangledstring += map[i]
+                else:
+                    mangledstring += i
+
+            return mangledstring
+
+        # Mangle doxygen arguments from WikiLink format to doxygen format
+        def mangle_doxygen_args(args):
+            charmap = { '<':'&lt; ',  '>':' &gt;',  '&':'&amp;'}
+            spaceargs = re.sub('%20', ' ', args)
+            mangledargs = ''
+            for i in spaceargs:
+                if i in charmap.keys():
+                    mangledargs += charmap[i]
+                else:
+                    mangledargs += i
+
+            return mangledargs
+
         self.log.debug('Looking up "%s" in documentation "%s"' % (file, doc))
 
         # Direct request for searching
@@ -275,8 +321,13 @@
 
         # Request for a documentation file.
         doc_ext_re = '|'.join(self.ext.split(' '))
-        if re.match(r'''^(.*)[.](%s)''' % doc_ext_re, file):
-            path, link = lookup(file, 'documentation')
+        m = re.match(r'''(^.*[.](?:%s))(#.*)?$''' % doc_ext_re, file)
+        if m != None:
+            if m.groups()[1] == None: # No anchor 
+                path, link = lookup(file, 'documentation')
+            else:
+                path, link = lookup(m.groups()[0], 'documentation')
+                link += m.groups()[1]
             if path:
                 return 'view', path, link
             else:
@@ -305,15 +356,82 @@
         #  - do something about dirs
         #  - expand with enum, defs, etc.
         #  - this doesn't work well with the CREATE_SUBDIRS Doxygen option
-        path, link = lookup('class%s.html' % file, 'class')
+
+        mangledfile = map_string(file, doxygen_file_map)
+
+        path, link = lookup('class%s.html' % mangledfile, 'class')
         if not path:
-            path, link = lookup('struct%s.html' % file, 'struct')
+            path, link = lookup('struct%s.html' % mangledfile, 'struct')
         if path:
             return 'view', path, link
 
+        # Try in the default_namespace
+        if self.default_namespace != "":
+            dnmangledfile = self.default_namespace + '_1_1' + mangledfile
+            path, link = lookup('class%s.html' % dnmangledfile, 'class')
+            if not path:
+                path, link = lookup('struct%s.html' % dnmangledfile, 'struct')
+            if path:
+                return 'view', path, link
+
+        # Could have a method attached to the classname...
+        # Remove the last ::XXX segment and try again
+        method_re = '::([^:]*)$'
+        nmfile = re.sub(method_re, "", file);
+
+        mangledfile = map_string(nmfile, doxygen_file_map)
+        namespace = ''
+
+        path, link = lookup('class%s.html' % mangledfile, 'class')
+        if not path:
+            path, link = lookup('struct%s.html' % mangledfile, 'struct')
+        if not path and self.default_namespace != "":
+            # Try in the default_namespace
+            namespace = self.default_namespace
+            dnmangledfile = self.default_namespace + '_1_1' + mangledfile
+            path, link = lookup('class%s.html' % dnmangledfile, 'class')
+            if not path:
+                path, link = lookup('struct%s.html' % dnmangledfile, 'struct')
+
+        if path:
+            self.log.debug('Found method %s %s' % (path, link))
+            member = re.search(method_re, file).group(1)
+            mangledmember = mangle_doxygen_args(member)
+            pieces = re.search("([^(]*)(\(([^)]*)\)(.*))?$", mangledmember)
+            classname = mangle_doxygen_args(nmfile)
+            if namespace != '':
+                classname = namespace + '::' + classname
+            re_name = map_string(classname + "::" + pieces.groups()[0], re_name_map)
+            if pieces.groups()[2] != None:
+                re_args = '(%s)%s' % (pieces.groups()[2], pieces.groups()[3])
+                re_args = map_string(re_args, re_name_map)
+            else:
+                re_args = None
+            self.log.debug("re_name = %s, re_args = %s" % (re_name, re_args))
+            fd = open(path)
+            filedata = fd.read()
+            anchor = None
+            anchor_pat='<!-- doxytag: member="([\w:;<>& !=\+\*\-/%]*)" ref="([\w]*)"(?: args="([\w, ()\*\&]*)")?'
+            for p in re.finditer(anchor_pat, filedata):
+                n = map_string(p.groups()[0], re_name_map)
+                #self.log.debug("match: %s %s %s" % (n, p.groups()[1], p.groups()[2]))
+                if n != re_name:
+                    continue
+                if re_args == None:
+                    anchor = p.groups()[1]
+                    break
+                a = map_string(p.groups()[2], re_name_map)
+                if a == re_args:
+                    anchor = p.groups()[1]
+                    break
+            if anchor != None:
+                link = link + '#' + anchor
+                self.log.debug('Found method in %s: %s %s' % (file, path, link))
+                return 'anchor', None, link
+
         # Revert to search...
         results = self._search_in_documentation(doc, [file])
-        class_ref = file+' Class Reference'
+        class_ref = file +' Class Reference'
         for result in results:
             self.log.debug('Reverted to search, found: ' + repr(result))
             name = result['name']
