Changeset 232

Show
Ignore:
Timestamp:
12/28/05 00:01:54 (3 years ago)
Author:
jparks
Message:

DoxygenPlugin:

Implement search functionality. For search to work the SEARCHENGINE option must be set to 'YES'.

Fixed the problem where the DoxygenPlugin was handling a request for '/'. It now ignores it.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • doxygenplugin/0.9/doxygentrac/doxygentrac.py

    r231 r232  
    1414from trac.web import IRequestHandler 
    1515from trac.web.chrome import INavigationContributor, ITemplateProvider 
     16from trac.Search import ISearchSource 
    1617 
     18def compare_rank(x, y): 
     19    if x['rank'] == y['rank']: 
     20        return 0 
     21    elif x['rank'] > y['rank']: 
     22        return -1 
     23     
     24    return 1 
    1725 
    1826class DoxygenPlugin(Component): 
    19     implements(INavigationContributor, IRequestHandler, ITemplateProvider) 
     27    implements(INavigationContributor, IRequestHandler, ITemplateProvider, ISearchSource) 
     28 
     29    # INavigationContributor methods 
    2030 
    2131    def get_active_navigation_item(self, req): 
     
    2434        yield 'mainnav', 'doxygen', '<a href="%s">Doxygen</a>' % (self.env.href.doxygen()) 
    2535 
     36    # IRequestHandler methods 
     37 
    2638    def match_request(self, req): 
    2739        if req.path_info == '/doxygen': 
    2840            req.args['path'] = ''.join([self.config.get('doxygen', 'path'), '/main.html']) 
    2941            return True 
    30         else
     42        elif req.path_info != '/'
    3143            path = ''.join([self.config.get('doxygen', 'path'), req.path_info]) 
    3244            req.args['path'] = path 
    33 #            self.log.debug('1 - doc = %s : %d' % (path, os.path.exists(path))) 
    3445            return os.path.exists(path) 
    3546 
     
    3849        return 'doxygen.cs', 'text/html' 
    3950 
     51    # ITemplateProvider methods 
     52 
    4053    def get_templates_dirs(self): 
    4154        from pkg_resources import resource_filename 
    4255        return [resource_filename(__name__, 'templates')] 
    4356     
     57    # ISearchProvider methods 
     58     
     59    def get_search_filters(self, req): 
     60        yield('doxygen', 'Doxygen') 
     61 
     62    def get_search_results(self, req, query, filters): 
     63        if not 'doxygen' in filters: 
     64            return 
     65        if query[0] == query[-1] == "'" or query[0] == query[-1] == '"': 
     66            keywords = [query[1:-1]] 
     67        else: 
     68            keywords = query.split(' ') 
     69   
     70        path = self.config.get('doxygen', 'path') 
     71        path = ''.join([path, '/search.idx']) 
     72 
     73        if os.path.exists(path):  
     74            fd = open(path) 
     75             
     76            results = [] 
     77            for keyword in keywords: 
     78                results += self._search(fd, keyword) 
     79             
     80            results.sort(compare_rank)             
     81             
     82            # use the creation time for the search.idx file for all results       
     83            creation = os.path.getctime(path) 
     84 
     85            for result in results: 
     86                yield result['url'], result['name'], creation, 'doxygen', None 
     87     
     88    # internal methods 
     89         
     90    def _search(self, fd, word): 
     91        results = [] 
     92        index = self._computeIndex(word) 
     93        if index != -1: 
     94            fd.seek(index * 4 + 4, 0) 
     95            index = self._readInt(fd) 
     96             
     97            if index: 
     98                fd.seek(index) 
     99                w = self._readString(fd) 
     100                matches = [] 
     101                while w != "": 
     102                    statIdx = self._readInt(fd) 
     103                    low = word.lower() 
     104                    if w.find(low) != -1: 
     105                        matches.append({'word' : word, 'match' : w, 'index' : statIdx, 'full' : len(low) == len(w)}) 
     106                    w = self._readString(fd) 
     107                 
     108                count = 0 
     109                totalHi = 0 
     110                totalFreqHi = 0 
     111                totalFreqLo = 0 
     112 
     113                for match in matches: 
     114                    multiplier = 1 
     115                    if match['full']: 
     116                        multiplier = 2 
     117 
     118                    fd.seek(match['index']) 
     119                    numDocs = self._readInt(fd) 
     120                    
     121                    for i in range(numDocs): 
     122                        idx = self._readInt(fd) 
     123                        freq = self._readInt(fd) 
     124                        results.append({'idx' : idx, 'freq' : freq >> 1, 'hi' : freq & 1, 'multi' : multiplier}) 
     125                        if freq & 1: 
     126                            totalHi += 1 
     127                            totalFreqHi += freq * multiplier 
     128                        else: 
     129                            totalFreqLo += freq * multiplier 
     130                     
     131                    for i in range(numDocs): 
     132                        fd.seek(results[count]['idx']) 
     133                        name = self._readString(fd) 
     134                        url = self._readString(fd) 
     135                        results[count]['name'] = name 
     136                        results[count]['url'] = url 
     137                        count += 1 
     138                 
     139                totalFreq = (totalHi + 1) * totalFreqLo + totalFreqHi 
     140                for i in range(count): 
     141                    freq = results[i]['freq'] 
     142                    multi = results[i]['multi'] 
     143                    if results[i]['hi']: 
     144                        results[i]['rank'] = float((freq * multi + totalFreqLo)) / float(totalFreq) 
     145                    else: 
     146                        results[i]['rank'] = float((freq * multi)) / float(totalFreq) 
     147                         
     148        return results 
     149 
     150    def _computeIndex(self, word): 
     151        if len(word) < 2: 
     152            return -1 
     153         
     154        hi = ord(word[0].lower()) 
     155        if hi == 0: 
     156            return -1 
     157             
     158        lo = ord(word[1].lower()) 
     159        if lo == 0: 
     160            return -1 
     161        
     162        return hi * 256 + lo 
     163         
     164    def _readInt(self, fd): 
     165        b1 = fd.read(1) 
     166        b2 = fd.read(1) 
     167        b3 = fd.read(1) 
     168        b4 = fd.read(1) 
     169         
     170        return (ord(b1) << 24) | (ord(b2) << 16) | (ord(b3) << 8) | ord(b4) 
     171     
     172     
     173    def _readString(self, fd): 
     174        byte = fd.read(1) 
     175        if byte == '\0': 
     176            return "" 
     177        result = byte 
     178        while byte != '\0': 
     179            byte = fd.read(1) 
     180            result = ''.join([result, byte]) 
     181     
     182        return result 
     183