Edgewall Software

Ticket #9230: 9230-display-rev-r9490.patch

File 9230-display-rev-r9490.patch, 25.5 KB (added by rblank, 2 years ago)

Introduce and use Repository.display_rev().

  • trac/versioncontrol/admin.py

    diff --git a/trac/versioncontrol/admin.py b/trac/versioncontrol/admin.py
    a b  
    299299        if not info.get('alias'): 
    300300            try: 
    301301                repos = RepositoryManager(self.env).get_repository(reponame) 
    302                 info['rev'] = repos.get_youngest_rev() 
     302                youngest_rev = repos.get_youngest_rev() 
     303                info['rev'] = youngest_rev 
     304                info['display_rev'] = repos.display_rev(youngest_rev) 
    303305            except Exception: 
    304306                pass 
    305307        return info 
  • trac/versioncontrol/api.py

    diff --git a/trac/versioncontrol/api.py b/trac/versioncontrol/api.py
    a b  
    856856        raise NotImplementedError 
    857857 
    858858    def normalize_rev(self, rev): 
    859         """Return a canonical representation of a revision. 
     859        """Return a (unique) canonical representation of a revision. 
    860860 
    861861        It's up to the backend to decide which string values of `rev`  
    862862        (usually provided by the user) should be accepted, and how they  
     
    871871    def short_rev(self, rev): 
    872872        """Return a compact representation of a revision in the repos.""" 
    873873        return self.normalize_rev(rev) 
     874 
     875    def display_rev(self, rev): 
     876        """Return a representation of a revision in the repos for displaying to 
     877        the user. 
     878         
     879        This can be a shortened revision string, e.g. for repositories using 
     880        long hashes. 
     881        """ 
     882        return self.normalize_rev(rev) 
    874883         
    875884    def get_changes(self, old_path, old_rev, new_path, new_rev, 
    876885                    ignore_ancestry=1): 
  • trac/versioncontrol/templates/admin_repositories.html

    diff --git a/trac/versioncontrol/templates/admin_repositories.html b/trac/versioncontrol/templates/admin_repositories.html
    a b  
    136136                  <py:when test="info.dir">$info.prettydir</py:when> 
    137137                  <em py:otherwise="">Alias of $info.alias</em> 
    138138                </td> 
    139                 <td><a py:if="info.rev" href="${href.changeset(info.rev, reponame) or None}">$info.rev</a></td> 
     139                <td><a py:if="info.rev" href="${href.changeset(info.rev, reponame) or None}">$info.display_rev</a></td> 
    140140              </tr> 
    141141            </tbody> 
    142142          </table> 
  • trac/versioncontrol/templates/browser.html

    diff --git a/trac/versioncontrol/templates/browser.html b/trac/versioncontrol/templates/browser.html
    a b  
    106106      <table py:if="properties or file" id="info" summary="Revision info"> 
    107107        <tr py:if="file"> 
    108108          <th scope="col" i18n:msg="rev, size, author, date"> 
    109             Revision <a href="${href.changeset(rev, reponame)}">$rev</a>, 
     109            Revision <a href="${href.changeset(rev, reponame)}">${display_rev(rev)}</a>, 
    110110            <span title="${_('%(size)s bytes', size=file.size)}">${pretty_size(file.size)}</span> 
    111111            checked in by ${authorinfo(file.changeset.author)}, ${dateinfo(file.changeset.date)} ago 
    112112            (<a href="${href.changeset(rev, reponame, created_path)}">diff</a>) 
  • trac/versioncontrol/templates/changeset.html

    diff --git a/trac/versioncontrol/templates/changeset.html b/trac/versioncontrol/templates/changeset.html
    a b  
    2727          log_href = href.log(reponame, new_path, rev=new_rev, stop_rev=old_rev); 
    2828          new_href = href.browser(reponame, new_path, rev=new_rev); 
    2929          old_href = href.browser(reponame, old_path, rev=old_rev); 
     30          old_drev = display_rev(old_rev); 
     31          new_drev = display_rev(new_rev); 
    3032            "> 
    3133        <py:when test="reponame"> 
    3234          <py:choose> 
    3335            <h1 py:when="changeset and restricted" i18n:msg="new_rev, reponame, new_path"> 
    34               Changeset <a title="Show full changeset" href="cset_href">$new_rev</a> in $reponame 
     36              Changeset <a title="Show full changeset" href="$cset_href">$new_drev</a> in $reponame 
    3537              for <a title="Show entry in browser" href="$new_href">$new_path</a> 
    3638            </h1> 
    3739            <h1 py:when="not changeset and restricted" i18n:msg="new_path, old_rev, new_rev, reponame"> 
    3840              Changes in <a title="Show entry in browser" href="$new_href">$new_path</a> 
    39               <a title="Show revision log" href="$log_href">[$old_rev:$new_rev]</a> in $reponame 
     41              <a title="Show revision log" href="$log_href">[$old_drev:$new_drev]</a> in $reponame 
    4042            </h1> 
    4143            <h1 py:when="not changeset and not restricted" i18n:msg="reponame, old_path, old_rev, new_path, new_rev"> 
    4244              Changes in $reponame 
    4345              from <a title="Show entry in browser" href="$old_href">$old_path</a> 
    44               at <a title="Show full changeset" href="$old_cset_href">r$old_rev</a> 
     46              at <a title="Show full changeset" href="$old_cset_href">r$old_drev</a> 
    4547              to <a title="Show entry in browser" href="$new_href">$new_path</a> 
    46               at <a title="Show full changeset" href="$cset_href">r$new_rev</a> 
     48              at <a title="Show full changeset" href="$cset_href">r$new_drev</a> 
    4749            </h1> 
    4850            <h1 py:otherwise="" i18n:msg="new_rev, reponame"> 
    49               Changeset <a py:strip="not annotated" href="$cset_href">$new_rev</a> in $reponame 
     51              Changeset <a py:strip="not annotated" href="$cset_href">$new_drev</a> in $reponame 
    5052            </h1> 
    5153          </py:choose> 
    5254        </py:when> 
    5355        <py:otherwise> 
    5456          <py:choose> 
    5557            <h1 py:when="changeset and restricted" i18n:msg="new_rev, new_path"> 
    56               Changeset <a title="Show full changeset" href="$cset_href">$new_rev</a> 
     58              Changeset <a title="Show full changeset" href="$cset_href">$new_drev</a> 
    5759              for <a title="Show entry in browser" href="$new_href">$new_path</a> 
    5860            </h1> 
    5961            <h1 py:when="not changeset and restricted" i18n:msg="new_path, old_rev, new_rev"> 
    6062              Changes in <a title="Show entry in browser" href="$new_href">$new_path</a> 
    61               <a title="Show revision log" href="$log_href">[$old_rev:$new_rev]</a> 
     63              <a title="Show revision log" href="$log_href">[$old_drev:$new_drev]</a> 
    6264            </h1> 
    6365            <h1 py:when="not changeset and not restricted" i18n:msg="old_path, old_rev, new_path, new_rev"> 
    6466              Changes 
    6567              from <a title="Show entry in browser" href="$old_href">$old_path</a> 
    66               at <a title="Show full changeset" href="$old_cset_href">r$old_rev</a> 
     68              at <a title="Show full changeset" href="$old_cset_href">r$old_drev</a> 
    6769              to <a title="Show entry in browser" href="$new_href">$new_path</a> 
    68               at <a title="Show full changeset" href="$cset_href">r$new_rev</a> 
     70              at <a title="Show full changeset" href="$cset_href">r$new_drev</a> 
    6971            </h1> 
    7072            <h1 py:otherwise="" i18n:msg="new_rev"> 
    71               Changeset <a py:strip="not annotated" href="$cset_href">$new_rev</a> 
     73              Changeset <a py:strip="not annotated" href="$cset_href">$new_drev</a> 
    7274            </h1> 
    7375          </py:choose> 
    7476        </py:otherwise> 
     
    9799          <div class="$cl"> </div> 
    98100          <py:choose> 
    99101          <a py:when="is_removal" href="$item.old.href" 
    100              title="${_('Show what was removed (content at revision %(old_rev)s)', old_rev=item.old.rev)}"> 
     102             title="${_('Show what was removed (content at revision %(old_rev)s)', old_rev=display_rev(item.old.rev))}"> 
    101103              $path 
    102104            </a> 
    103105            <a py:otherwise="" title="Show entry in browser" href="$item.new.href"> 
     
    108110          <py:if test="item.old and item.old.get('path') and item.change == 'copy' or item.change == 'move'"> 
    109111            <small><em i18n:msg="kind, old_path"> 
    110112              ($kind from <a href="$item.old.href" 
    111                              title="${_('Show original file (revision %(old_rev)s)', old_rev=item.old.rev)}"> 
     113                             title="${_('Show original file (revision %(old_rev)s)', old_rev=display_rev(item.old.rev))}"> 
    112114                $item.old.path</a>) 
    113115            </em></small> 
    114116          </py:if> 
  • trac/versioncontrol/templates/dir_entries.html

    diff --git a/trac/versioncontrol/templates/dir_entries.html b/trac/versioncontrol/templates/dir_entries.html
    a b  
    1616          <span title="${_('%(size)s bytes', size=entry.content_length)}">${pretty_size(entry.content_length)}</span> 
    1717        </td> 
    1818        <td class="rev"> 
    19           <a title="View Revision Log" href="${href.log(reponame, entry.path, rev=rev)}">$entry.rev</a> 
     19          <a title="View Revision Log" href="${href.log(reponame, entry.path, rev=rev)}">${display_rev(entry.rev)}</a> 
    2020          <a title="View Changeset" class="chgset" href="${href.changeset(change.rev, reponame)}">&nbsp;</a> 
    2121        </td> 
    2222        <td class="age" style="${chgset_view and dir.timerange and 'border-color: rgb(%s,%s,%s)' % 
  • trac/versioncontrol/templates/path_links.html

    diff --git a/trac/versioncontrol/templates/path_links.html b/trac/versioncontrol/templates/path_links.html
    a b  
    2828      >$part.name</a><py:if test="not last" 
    2929        ><span class="pathentry sep">/</span></py:if></py:with></py:for> 
    3030<!--! @ revision        (FIXME check the data, this can sometimes be wrong) --> 
    31 <py:if test="rev"><span class="pathentry sep">@</span> 
     31<py:if test="rev" py:with="drev = display_rev(rev)"><span class="pathentry sep">@</span> 
    3232  <a class="pathentry" href="${href.changeset(rev, reponame)}"  
    33      title="${_('View changeset %(rev)s', rev=rev)}">$rev</a> 
     33     title="${_('View changeset %(rev)s', rev=drev)}">$drev</a> 
    3434</py:if> 
    3535<br style="clear: both" /> 
    3636 
  • trac/versioncontrol/templates/repository_index.html

    diff --git a/trac/versioncontrol/templates/repository_index.html b/trac/versioncontrol/templates/repository_index.html
    a b  
    2020          <td class="size" /> 
    2121          <td class="rev"> 
    2222            <py:if test="not err"> 
    23               <a title="View Revision Log" href="${href.log(repos.reponame)}">$change.rev</a> 
     23              <a title="View Revision Log" href="${href.log(repos.reponame)}">${repos.display_rev(change.rev)}</a> 
    2424              <a title="View Changeset" class="chgset" href="${href.changeset(change.rev, repos.reponame)}">&nbsp;</a> 
    2525            </py:if> 
    2626          </td> 
  • trac/versioncontrol/templates/revisionlog.html

    diff --git a/trac/versioncontrol/templates/revisionlog.html b/trac/versioncontrol/templates/revisionlog.html
    a b  
    123123                  <td class="diff"> 
    124124                    <input type="radio" name="old" value="${item.rev}@${item.path}" 
    125125                           checked="${idx == (len(items) - 1) or None}"  
    126                            title="${_('From r%(rev)s', rev=item.rev)}" /> 
     126                           title="${_('From [%(rev)s]', rev=display_rev(item.rev))}" /> 
    127127                    <input type="radio" name="new" value="${item.rev}@${item.path}" 
    128128                           checked="${idx == 0 or None}"  
    129                            title="${_('To r%(rev)s', rev=item.rev)}" /> 
     129                           title="${_('To [%(rev)s]', rev=display_rev(item.rev))}" /> 
    130130                  </td> 
    131131                  <py:when test="not is_separator"> 
    132132                    <td class="change" style="padding-left: ${item.depth}em"> 
     
    138138                    </td> 
    139139                    <td class="rev"> 
    140140                      <a href="${href.browser(reponame, item.path, rev=item.existing_rev)}" 
    141                          title="${_('Browse at revision %(rev)s', rev=item.existing_rev)}"> 
    142                         @$item.existing_rev</a> 
     141                         title="${_('Browse at revision %(rev)s', rev=display_rev(item.existing_rev))}"> 
     142                        @${display_rev(item.existing_rev)}</a> 
    143143                      <py:choose test="item.change"> 
    144144                        <a py:when="'delete'" class="chgset" href="${href.changeset(item.rev)}" 
    145                            title="${_('View removal changeset [%(rev)s]', rev=item.rev)}">&nbsp;</a> 
     145                           title="${_('View removal changeset [%(rev)s]', rev=display_rev(item.rev))}">&nbsp;</a> 
    146146                        <a py:otherwise="" class="chgset" href="${href.changeset(item.rev, reponame, item.path)}" 
    147147                           title="${_('View changeset [%(rev)s] restricted to %(path)s', 
    148                                       rev=item.rev, path=item.path)}">&nbsp;</a> 
     148                                      rev=display_rev(item.rev), path=item.path or '/')}">&nbsp;</a> 
    149149                      </py:choose> 
    150150                    </td> 
    151151                    <td class="age" py:content="dateinfo(change.date)" /> 
  • trac/versioncontrol/templates/revisionlog.rss

    diff --git a/trac/versioncontrol/templates/revisionlog.rss b/trac/versioncontrol/templates/revisionlog.rss
    a b  
    1919                   item_context = context('changeset', change.rev, parent=repos.resource)"> 
    2020      <xi:include href="author_or_creator.rss" py:with="author = change.author"/> 
    2121      <pubDate>${http_date(change.date)}</pubDate> 
    22       <title>Revision $item.rev: ${shorten_line(change.message)}</title> 
     22      <title>Revision ${display_rev(item.rev)}: ${shorten_line(change.message)}</title> 
    2323      <link>${abs_href.changeset(item.rev, reponame, item.path)}</link> 
    2424      <guid isPermaLink="false">${abs_href.changeset(item.rev, reponame, item.path)}</guid> 
    2525      <description py:with="m = change.message">${ 
  • trac/versioncontrol/templates/revisionlog.txt

    diff --git a/trac/versioncontrol/templates/revisionlog.txt b/trac/versioncontrol/templates/revisionlog.txt
    a b  
    66  
    77{% for item in items %}\ 
    88{%   with change = changes[item.rev]; extra = extra_changes[item.rev] %}\ 
    9 ${http_date(change.date)} ${format_author(change.author)} [$item.rev] 
     9${http_date(change.date)} ${format_author(change.author)} [${display_rev(item.rev)}] 
    1010{%     for idx, file in enumerate(extra.files) %}\ 
    1111{%       if 'FILE_VIEW' in perm(repos.resource.child('source', file, version=change.rev)) %}\ 
    1212        * $file (${dict(edit='modified', add='added', delete='deleted', 
  • trac/versioncontrol/web_ui/browser.py

    diff --git a/trac/versioncontrol/web_ui/browser.py b/trac/versioncontrol/web_ui/browser.py
    a b  
    356356        # Find node for the requested path/rev 
    357357        context = Context.from_request(req) 
    358358        node = None 
     359        display_rev = lambda rev: rev 
    359360        if repos: 
    360361            try: 
    361362                if rev: 
     
    370371 
    371372            context = context(repos.resource.child('source', path, 
    372373                                                   version=rev_or_latest)) 
     374            display_rev = repos.display_rev 
     375 
    373376        # Prepare template data 
    374377        path_links = get_path_links(req.href, reponame, path, rev, 
    375378                                    order, desc) 
     
    394397            'context': context, 'reponame': reponame, 'repos': repos, 
    395398            'repoinfo': repoinfo, 
    396399            'path': path, 'rev': node and node.rev, 'stickyrev': rev, 
     400            'display_rev': display_rev, 
    397401            'created_path': node and node.created_path, 
    398402            'created_rev': node and node.created_rev, 
    399403            'properties': properties_data, 
     
    421425                    href = req.href.browser(reponame, 
    422426                                            node.created_path, rev=prev_rev) 
    423427                    add_link(req, 'prev', href, 
    424                              _('Revision %(num)s', num=prev_rev)) 
     428                             _('Revision %(num)s', num=display_rev(prev_rev))) 
    425429                if rev is not None: 
    426430                    add_link(req, 'up', req.href.browser(reponame, 
    427431                                                         node.created_path)) 
     
    431435                    href = req.href.browser(reponame, node.created_path, 
    432436                                            rev=next_rev) 
    433437                    add_link(req, 'next', href, 
    434                              _('Revision %(num)s', num=next_rev)) 
     438                             _('Revision %(num)s', num=display_rev(next_rev))) 
    435439                prevnext_nav(req, _('Previous Revision'), _('Next Revision'), 
    436440                             _('Latest Revision')) 
    437441            else: 
  • trac/versioncontrol/web_ui/changeset.py

    diff --git a/trac/versioncontrol/web_ui/changeset.py b/trac/versioncontrol/web_ui/changeset.py
    a b  
    331331            rpath = new_path.replace('/','_') 
    332332            if chgset: 
    333333                if restricted: 
    334                     filename = 'changeset_%s_r%s' % (rpath, new) 
     334                    filename = 'changeset_%s_%s' % (rpath, new) 
    335335                else: 
    336                     filename = 'changeset_r%s' % new 
     336                    filename = 'changeset_%s' % new 
    337337            else: 
    338338                if restricted: 
    339                     filename = 'diff-%s-from-r%s-to-r%s' \ 
     339                    filename = 'diff-%s-from-%s-to-%s' \ 
    340340                                  % (rpath, old, new) 
    341341                elif old_path == '/': # special case for download (#238) 
    342                     filename = '%s-r%s' % (rpath, old) 
     342                    filename = '%s-%s' % (rpath, old) 
    343343                else: 
    344                     filename = 'diff-from-%s-r%s-to-%s-r%s' \ 
     344                    filename = 'diff-from-%s-%s-to-%s-%s' \ 
    345345                               % (old_path.replace('/','_'), old, rpath, new) 
    346346            if format == 'diff': 
    347347                self._render_diff(req, filename, repos, data) 
     
    381381    def _render_html(self, req, repos, chgset, restricted, xhr, data): 
    382382        """HTML version""" 
    383383        data['restricted'] = restricted 
     384        display_rev = repos.display_rev 
     385        data['display_rev'] = display_rev 
    384386        browser = BrowserModule(self.env) 
    385387        reponame = repos.reponame or None 
    386388 
     
    406408                    yield old_node, new_node, kind, change 
    407409 
    408410            def _changeset_title(rev): 
     411                rev = display_rev(rev) 
    409412                if restricted: 
    410413                    return _('Changeset %(id)s for %(path)s', id=rev, 
    411414                             path=path) 
     
    436439                else: 
    437440                    add_link(req, 'first',  
    438441                             req.href.changeset(oldest_rev, reponame), 
    439                              _('Changeset %(id)s', id=oldest_rev)) 
     442                             _('Changeset %(id)s', id=display_rev(oldest_rev))) 
    440443                    prev_path = data['old_path'] 
    441444                    prev_rev = repos.previous_rev(chgset.rev) 
    442445                    if prev_rev: 
     
    457460                else: 
    458461                    add_link(req, 'last',  
    459462                             req.href.changeset(youngest_rev, reponame), 
    460                              _('Changeset %(id)s', id=youngest_rev)) 
     463                             _('Changeset %(id)s', 
     464                               id=display_rev(youngest_rev))) 
    461465                    next_rev = repos.next_rev(chgset.rev) 
    462466                    if next_rev: 
    463467                        next_href = req.href.changeset(next_rev, reponame) 
     
    484488                reponame, node.created_path, rev=node.created_rev, 
    485489                annotate=annotated and 'blame' or None) 
    486490            title = _('Show revision %(rev)s of this file in browser', 
    487                       rev=node.rev) 
     491                      rev=display_rev(node.rev)) 
    488492            return {'path': node.path, 'rev': node.rev, 
    489493                    'shortrev': repos.short_rev(node.rev), 
    490494                    'href': href, 'title': title} 
     
    630634                        href = req.href.changeset(new_node.rev, reponame, 
    631635                                                  new_node.path) 
    632636                        title = _('Show the changeset %(id)s restricted to ' 
    633                                   '%(path)s', id=new_node.rev, 
     637                                  '%(path)s', id=display_rev(new_node.rev), 
    634638                                  path=new_node.path) 
    635639                    else: 
    636640                        href = req.href.changeset( 
     
    640644                            old_path=pathjoin(repos.reponame,  
    641645                                              old_node.created_path)) 
    642646                        title = _('Show the %(range)s differences restricted ' 
    643                                   'to %(path)s', range='r%s:%s' % ( 
    644                                       old_node.rev, new_node.rev), 
     647                                  'to %(path)s', range='[%s:%s]' % ( 
     648                                      display_rev(old_node.rev), 
     649                                      display_rev(new_node.rev)), 
    645650                                  path=new_node.path) 
    646651                    info['href'] = href 
    647652                    info['title'] = old_node and title 
     
    782787    def title_for_diff(self, data): 
    783788        if data['new_path'] == data['old_path']: 
    784789            # ''diff between 2 revisions'' mode 
    785             return 'Diff r%s:%s for %s' \ 
     790            return 'Diff [%s:%s] for %s' \ 
    786791                   % (data['old_rev'] or 'latest', data['new_rev'] or 'latest', 
    787792                      data['new_path'] or '/') 
    788793        else: 
     
    9991004                             single and 1 or 2, repo=', '.join(repos_for_uid)) 
    10001005        else: 
    10011006            title = ngettext('Changeset ', 'Changesets ', single and 1 or 2) 
     1007        drev_a = older_cset.repos.display_rev(rev_a) 
    10021008        if single: 
    1003             title = tag(title, tag.em('[%s]' % rev_a)) 
     1009            title = tag(title, tag.em('[%s]' % drev_a)) 
    10041010        else: 
    1005             title = tag(title, tag.em('[%s-%s]' % (rev_a, rev_b))) 
     1011            drev_b = cset.repos.display_rev(rev_b) 
     1012            title = tag(title, tag.em('[%s-%s]' % (drev_a, drev_b))) 
    10061013        if field == 'title': 
    10071014            return title 
    10081015        elif field == 'summary': 
  • trac/versioncontrol/web_ui/log.py

    diff --git a/trac/versioncontrol/web_ui/log.py b/trac/versioncontrol/web_ui/log.py
    a b  
    104104                rev = revranges.b 
    105105            except ValueError: 
    106106                pass 
    107         rev = unicode(repos.normalize_rev(rev))     
     107        rev = unicode(repos.normalize_rev(rev)) 
     108        display_rev = repos.display_rev 
    108109 
    109110        # The `history()` method depends on the mode: 
    110111        #  * for ''stop on copy'' and ''follow copies'', it's `Node.history()` 
     
    195196                # FIXME: we should send a 404 error here 
    196197                raise TracError(_("The file or directory '%(path)s' doesn't " 
    197198                    "exist at revision %(rev)s or at any previous revision.",  
    198                     path=path, rev=rev), _('Nonexistent path')) 
     199                    path=path, rev=display_rev(rev)), _('Nonexistent path')) 
    199200 
    200201        def make_log_href(path, **args): 
    201202            link_rev = rev 
     
    223224                                                     revs=next_revranges) 
    224225                add_link(req, 'next', older_revisions_href, 
    225226                    _('Revision Log (restarting at %(path)s, rev. %(rev)s)', 
    226                     path=next_path, rev=next_rev)) 
     227                    path=next_path, rev=display_rev(next_rev))) 
    227228            # only show fully 'limit' results, use `change == None` as a marker 
    228229            info[-1]['change'] = None 
    229230         
     
    258259            'context': Context.from_request(req, 'source', path, 
    259260                                            parent=repos.resource), 
    260261            'reponame': repos.reponame or None, 'repos': repos, 
    261             'path': path, 'rev': rev, 'stop_rev': stop_rev,  
    262             'revranges': revranges, 
     262            'path': path, 'rev': rev, 'stop_rev': stop_rev, 
     263            'display_rev': display_rev, 'revranges': revranges, 
    263264            'mode': mode, 'verbose': verbose, 'limit' : limit, 
    264265            'items': info, 'changes': changes, 
    265266            'email_map': email_map, 'extra_changes': extra_changes, 
  • trac/versioncontrol/web_ui/tests/wikisyntax.py

    diff --git a/trac/versioncontrol/web_ui/tests/wikisyntax.py b/trac/versioncontrol/web_ui/tests/wikisyntax.py
    a b  
    231231<p> 
    232232<a class="changeset" href="/changeset?new_path=branch&amp;old_path=trunk" title="Diff from trunk@latest to branch@latest">diff:trunk//branch</a> 
    233233<a class="changeset" href="/changeset?new=23&amp;new_path=branch&amp;old=12&amp;old_path=trunk" title="Diff from trunk@12 to branch@23">diff:trunk@12//branch@23</a> 
    234 <a class="changeset" href="/changeset?new=23&amp;new_path=trunk&amp;old=12&amp;old_path=trunk" title="Diff r12:23 for trunk">diff:trunk@12:23</a> 
    235 <a class="changeset" href="/changeset?new=23&amp;old=12" title="Diff r12:23 for /">diff:@12:23</a> 
     234<a class="changeset" href="/changeset?new=23&amp;new_path=trunk&amp;old=12&amp;old_path=trunk" title="Diff [12:23] for trunk">diff:trunk@12:23</a> 
     235<a class="changeset" href="/changeset?new=23&amp;old=12" title="Diff [12:23] for /">diff:@12:23</a> 
    236236</p> 
    237237------------------------------ 
    238238============================== diff: link resolver + query 
     
    246246diff:// 
    247247------------------------------ 
    248248<p> 
    249 <a class="changeset" title="Diff rlatest:latest for /">diff://</a> 
     249<a class="changeset" title="Diff [latest:latest] for /">diff://</a> 
    250250</p> 
    251251------------------------------ 
    252252"""