Updated diff to process a unified diff for display

This commit is contained in:
Correl Roush 2010-11-19 13:44:30 -05:00
parent 6b747d99cb
commit 6d9bc6777b
3 changed files with 50 additions and 42 deletions

View file

@ -1,3 +1,4 @@
import re
import difflib import difflib
from datetime import datetime from datetime import datetime
@ -30,39 +31,48 @@ class Diff(object):
self.a = None self.a = None
self.b = None self.b = None
self.type = 0 self.type = 0
def unified(self): def unified(self, context=3):
a = self.a.data.split('\n') if self.a else [] a = self.a.data.split('\n') if self.a else []
b = self.b.data.split('\n') if self.b else [] b = self.b.data.split('\n') if self.b else []
diff = difflib.unified_diff( diff = difflib.unified_diff(
a, a,
b, b,
fromfile=self.a.path, fromfile=self.a.path,
tofile=self.b.path) tofile=self.b.path,
return '\n'.join(diff) n=context,
lineterm='')
return "\n".join(diff)
def changes(self, context=3): def changes(self, context=3):
a = self.a.data.split('\n') if self.a else [] "Parses the unified diff into a data structure for easy display"
b = self.b.data.split('\n') if self.b else []
differ = difflib.Differ()
# Locate changes so we can mark context lines
i = 0
changes = [] changes = []
for change in differ.compare(a, b):
if change[0] in ['+', '-']:
changes.append(i)
i += 1
i = 0
line_a = 0 line_a = 0
line_b = 0 line_b = 0
for change in differ.compare(a, b): if context == None:
type = change[:2].strip() context = max(
text = change[2:] len(self.a.data.split('\n')) if self.a else 0,
if type == '?': len(self.b.data.split('\n')) if self.b else 0)
# Change information. Discard it for now. for line in self.unified(context).split('\n')[2:]:
i += 1 if line.startswith('@@'):
print 'skip ?' pattern = r'\-(\d+)(,\d+)? \+(\d+)(,\d+)?'
info = re.findall(pattern, line)
line_a = int(info[0][0])
line_b = int(info[0][2])
change = {
'type': '@',
'text': line,
'line_a': line_a,
'line_b': line_b,
}
changes.append(change)
continue continue
type = line[0]
text = line[1:]
change = {
'type': type,
'text': text,
'line_a': line_a,
'line_b': line_b,
}
if type == '+': if type == '+':
line_b += 1 line_b += 1
elif type == '-': elif type == '-':
@ -70,21 +80,9 @@ class Diff(object):
else: else:
line_a += 1 line_a += 1
line_b += 1 line_b += 1
if context and not type: changes.append(change)
# Check to see if we're in range of a change return changes
nearby = [c for c in changes if abs(i - c) <= context + 1]
if not nearby:
i += 1
print 'skip nc'
continue
result = {
'type': type,
'line_a': line_a,
'line_b': line_b,
'text': text,
}
yield result
i += 1
def html(self): def html(self):
a = self.a.data.split('\n') if self.a.data else [] a = self.a.data.split('\n') if self.a.data else []
b = self.b.data.split('\n') if self.b.data else [] b = self.b.data.split('\n') if self.b.data else []

View file

@ -49,6 +49,10 @@ table.diff {
table.diff td { table.diff td {
padding-left: .3em; padding-left: .3em;
padding-right: .3em; padding-right: .3em;
white-space: nowrap;
}
table.diff .break {
background-color: #babaee;
} }
table.diff .number { table.diff .number {
width: 3em; width: 3em;

View file

@ -37,11 +37,17 @@
{% if diff.b %}{{ diff.b.path }}{% else %}(Deleted){% endif %} {% if diff.b %}{{ diff.b.path }}{% else %}(Deleted){% endif %}
{% endif %} {% endif %}
{% for change in diff.changes %} {% for change in diff.changes %}
<tr class="{% if change.type == '+' %}add{% endif %}{% if change.type == '-' %}del{% endif %}"> {% if change.type == '@' %}
<td class="number">{% if change.type != '+' %}{{ change.line_a }}{% endif %}</td> <tr class="break">
<td class="number">{% if change.type != '-' %}{{ change.line_b }}{% endif %}</td> <td colspan="3">{{ change.text }}</td>
<td class="text">{{ change.text }}</td> </tr>
</tr> {% else %}
<tr class="{% if change.type == '+' %}add{% endif %}{% if change.type == '-' %}del{% endif %}">
<td class="number">{% if change.type != '+' %}{{ change.line_a }}{% endif %}</td>
<td class="number">{% if change.type != '-' %}{{ change.line_b }}{% endif %}</td>
<td class="text">{{ change.text }}</td>
</tr>
{% endif %}
{% endfor %} {% endfor %}
</table> </table>
{% endfor %} {% endfor %}