25
25
# This code originally by Scott Moonen, used with permission.
26
def diff(request, old, new, old_top='', new_top='', old_bottom='', new_bottom='', old_top_class='', new_top_class='', old_bottom_class='', new_bottom_class=''):
26
def diff(request, old, new):
27
27
""" Find changes between old and new and return
28
28
HTML markup visualising them.
30
@param old: old text [unicode]
31
@param new: new text [unicode]
32
@param old_top: Custom html for adding ontop of old revision column (optional)
33
@param old_bottom: Custom html for adding at bottom of old revision column (optional)
34
@param new_top: Custom html for adding ontop of new revision column (optional)
35
@param new_bottom: Custom html for adding at bottom of new revision column (optional)
36
@param old_top_class: Custom class for <td> with old_top content (optional)
37
@param new_top_class: Custom class for <td> with new_top content (optional)
38
@param old_bottom_class: Custom class for <td> with old_bottom content (optional)
39
@param new_bottom_class: Custom class for <td> with new_bottom content (optional)
41
30
_ = request.getText
42
31
t_line = _("Line") + " %d"
47
36
seqobj = difflib.SequenceMatcher(None, seq1, seq2)
48
37
linematch = seqobj.get_matching_blocks()
39
if len(seq1) == len(seq2) and linematch[0] == (0, 0, len(seq1)):
41
return " - " + _("No differences found!")
51
46
<table class="diff">
54
if old_top or new_top:
55
result += '<tr><td class="%s">%s</td><td class="%s">%s</td></tr>' % (old_top_class, old_top, new_top_class, new_top)
57
if len(seq1) == len(seq2) and linematch[0] == (0, 0, len(seq1)):
59
result += '<tr><td class="diff-same" colspan="2">' + _("No differences found!") + '</td></tr>'
63
<td class="diff-removed"><span>%s</span></td>
64
<td class="diff-added"><span>%s</span></td>
48
<td class="diff-removed">
53
<td class="diff-added">
66
59
""" % (_('Deletions are marked like this.'), _('Additions are marked like this.'), )
70
# Print all differences
71
for match in linematch:
72
# Starts of pages identical?
73
if lastmatch == match[0:2]:
74
lastmatch = (match[0] + match[2], match[1] + match[2])
76
llineno, rlineno = lastmatch[0]+1, lastmatch[1]+1
61
# Print all differences
62
for match in linematch:
63
# Starts of pages identical?
64
if lastmatch == match[0:2]:
65
lastmatch = (match[0] + match[2], match[1] + match[2])
67
llineno, rlineno = lastmatch[0]+1, lastmatch[1]+1
78
69
<tr class="diff-title">
82
77
""" % (request.formatter.line_anchorlink(1, llineno) + request.formatter.text(t_line % llineno) + request.formatter.line_anchorlink(0),
83
request.formatter.line_anchorlink(1, rlineno) + request.formatter.text(t_line % rlineno) + request.formatter.line_anchorlink(0))
87
linecount = max(match[0] - lastmatch[0], match[1] - lastmatch[1])
88
for line in range(linecount):
89
if line < match[0] - lastmatch[0]:
92
leftpane += seq1[lastmatch[0] + line]
93
if line < match[1] - lastmatch[1]:
96
rightpane += seq2[lastmatch[1] + line]
98
charobj = difflib.SequenceMatcher(None, leftpane, rightpane)
99
charmatch = charobj.get_matching_blocks()
101
if charobj.ratio() < 0.5:
102
# Insufficient similarity.
104
leftresult = """<span>%s</span>""" % indent(escape(leftpane))
109
rightresult = """<span>%s</span>""" % indent(escape(rightpane))
78
request.formatter.line_anchorlink(1, rlineno) + request.formatter.text(t_line % rlineno) + request.formatter.line_anchorlink(0))
82
linecount = max(match[0] - lastmatch[0], match[1] - lastmatch[1])
83
for line in range(linecount):
84
if line < match[0] - lastmatch[0]:
87
leftpane += seq1[lastmatch[0] + line]
88
if line < match[1] - lastmatch[1]:
91
rightpane += seq2[lastmatch[1] + line]
93
charobj = difflib.SequenceMatcher(None, leftpane, rightpane)
94
charmatch = charobj.get_matching_blocks()
96
if charobj.ratio() < 0.5:
97
# Insufficient similarity.
99
leftresult = """<span>%s</span>""" % indent(escape(leftpane))
113
# Some similarities; markup changes.
104
rightresult = """<span>%s</span>""" % indent(escape(rightpane))
118
for thismatch in charmatch:
119
if thismatch[0] - charlast[0] != 0:
120
leftresult += """<span>%s</span>""" % indent(
121
escape(leftpane[charlast[0]:thismatch[0]]))
122
if thismatch[1] - charlast[1] != 0:
123
rightresult += """<span>%s</span>""" % indent(
124
escape(rightpane[charlast[1]:thismatch[1]]))
125
leftresult += escape(leftpane[thismatch[0]:thismatch[0] + thismatch[2]])
126
rightresult += escape(rightpane[thismatch[1]:thismatch[1] + thismatch[2]])
127
charlast = (thismatch[0] + thismatch[2], thismatch[1] + thismatch[2])
129
leftpane = '<br>'.join([indent(x) for x in leftresult.splitlines()])
130
rightpane = '<br>'.join([indent(x) for x in rightresult.splitlines()])
132
# removed width="50%%"
108
# Some similarities; markup changes.
113
for thismatch in charmatch:
114
if thismatch[0] - charlast[0] != 0:
115
leftresult += """<span>%s</span>""" % indent(
116
escape(leftpane[charlast[0]:thismatch[0]]))
117
if thismatch[1] - charlast[1] != 0:
118
rightresult += """<span>%s</span>""" % indent(
119
escape(rightpane[charlast[1]:thismatch[1]]))
120
leftresult += escape(leftpane[thismatch[0]:thismatch[0] + thismatch[2]])
121
rightresult += escape(rightpane[thismatch[1]:thismatch[1] + thismatch[2]])
122
charlast = (thismatch[0] + thismatch[2], thismatch[1] + thismatch[2])
124
leftpane = '<br>\n'.join([indent(x) for x in leftresult.splitlines()])
125
rightpane = '<br>\n'.join([indent(x) for x in rightresult.splitlines()])
127
# removed width="50%%"
135
<td class="diff-removed">%s</td>
136
<td class="diff-added">%s</td>
130
<td class="diff-removed">
133
<td class="diff-added">
138
137
""" % (leftpane, rightpane)
140
lastmatch = (match[0] + match[2], match[1] + match[2])
142
if old_bottom or new_bottom:
143
result += '<tr><td class="%s">%s</td><td class="%s">%s</td></tr>' % (old_top_class, old_top, new_top_class, new_top)
139
lastmatch = (match[0] + match[2], match[1] + match[2])
145
141
result += '</table>\n'