Edgewall Software
Modify

Opened 8 hours ago

Last modified 4 hours ago

#13861 new enhancement

Improve diff display

Reported by: Dirk Stöcker Owned by:
Priority: normal Milestone:
Component: version control Version: 1.6
Severity: normal Keywords:
Cc: Branch:
Release Notes:
API Changes:
Internal Changes:

Description (last modified by Dirk Stöcker)

The diff functionality in trac has a very simple method to show changes in a line. In JOSM wiki we use this diff a lot for translation and I wanted a better display. Attached is a patch improving trac/versioncontrol/diff.py

  • diff.py

    old new  
    3030    return ' '.join(_whitespace_split(text))
    3131
    3232
    33 def get_change_extent(str1, str2):
    34     """Determines the extent of differences between two strings.
     33def get_change_extents(str1, str2):
     34    """Determines the extents of differences between two strings.
    3535
    36     Returns a pair containing the offset at which the changes start,
    37     and the negative offset at which the changes end.
    38 
    39     If the two strings have neither a common prefix nor a common
    40     suffix, ``(0, 0)`` is returned.
     36    Returns a list of typles containing the offsets at which the changes start,
     37    and the offsets at which the changes end:
     38    [(startstr1,endstr1,startstr2,endstr2),(...)].
     39    The list is sorted from the last to the first.
    4140    """
     41    done = []
    4242    start = 0
    43     limit = min(len(str1), len(str2))
     43    minlen = 7
     44    l1 = len(str1)
     45    l2 = len(str2)
     46    limit = min(l1, l2)
    4447    while start < limit and str1[start] == str2[start]:
    4548        start += 1
    4649    end = -1
    4750    limit = limit - start
    4851    while -end <= limit and str1[end] == str2[end]:
    4952        end -= 1
    50     return start, end + 1
     53    new = [(start, l1 + end + 1, start, l2 + end + 1)]
     54    matcher = difflib.SequenceMatcher(None, str1, str2)
     55    while new:
     56        n = []
     57        for e in new:
     58            if min(e[1]-e[0],e[3]-e[2]) < minlen+2:
     59                done.append(e)
     60            else:
     61                (s1,s2,s) = matcher.find_longest_match(e[0], e[1], e[2], e[3])
     62                if s < minlen:
     63                    done.append(e)
     64                else:
     65                    n.append((e[0],s1,e[2],s2))
     66                    n.append((s1+s,e[1],s2+s,e[3]))
     67        new = n
     68    return sorted(done, reverse=True)
    5169
    5270
    5371def get_filtered_hunks(fromlines, tolines, context=None,
     
    207225            if tag == 'replace' and i2 - i1 == j2 - j1:
    208226                for i in range(i2 - i1):
    209227                    fromline, toline = fromlines[i1 + i], tolines[j1 + i]
    210                     (start, end) = get_change_extent(fromline, toline)
    211                     if start != 0 or end != 0:
    212                         last = end + len(fromline)
    213                         fromlines[i1 + i] = (
    214                             fromline[:start] + '\0' + fromline[start:last] +
    215                             '\1' + fromline[last:])
    216                         last = end+len(toline)
    217                         tolines[j1 + i] = (
    218                             toline[:start] + '\0' + toline[start:last] +
    219                             '\1' + toline[last:])
     228                    fromlen = len(fromline)
     229                    tolen = len(toline)
     230                    for fromstart, fromend, tostart, toend in get_change_extents(fromline, toline):
     231                        if fromstart != fromend and (fromstart != 0 or fromend != fromlen):
     232                            fromline = (
     233                                fromline[:fromstart] + '\0' + fromline[fromstart:fromend] +
     234                                '\1' + fromline[fromend:])
     235                        if tostart != toend and (tostart != 0 or toend != tolen):
     236                            toline = (
     237                                toline[:tostart] + '\0' + toline[tostart:toend] +
     238                                    '\1' + toline[toend:])
     239                    fromlines[i1 + i] = fromline
     240                    tolines[j1 + i] = toline
    220241            yield tag, i1, i2, j1, j2
    221242
    222243    changes = []

old:
old state
new:
new state

Attachments (3)

update.diff (3.5 KB ) - added by Dirk Stöcker 8 hours ago.
The diff as file
alt.png (183.6 KB ) - added by Dirk Stöcker 8 hours ago.
old state
neu.png (179.5 KB ) - added by Dirk Stöcker 8 hours ago.
new state

Download all attachments as: .zip

Change History (5)

by Dirk Stöcker, 8 hours ago

Attachment: update.diff added

The diff as file

by Dirk Stöcker, 8 hours ago

Attachment: alt.png added

old state

by Dirk Stöcker, 8 hours ago

Attachment: neu.png added

new state

comment:1 by Dirk Stöcker, 8 hours ago

Description: modified (diff)

comment:2 by Jun Omae, 4 hours ago

That is the same of (or probably related) #6858. I'll try the patch.

Modify Ticket

Change Properties
Set your email in Preferences
Action
as new The ticket will remain with no owner.
The ticket will be disowned.
as The resolution will be set. Next status will be 'closed'.
The owner will be changed from (none) to anonymous. Next status will be 'assigned'.

Add Comment


E-mail address and name can be saved in the Preferences .
 
Note: See TracTickets for help on using tickets.