-
Notifications
You must be signed in to change notification settings - Fork 104
/
Copy pathdiff.py
88 lines (75 loc) · 2.55 KB
/
diff.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
"""
lodgeit.lib.diff
~~~~~~~~~~~~~~~~
Render a nice diff between two things.
:copyright: 2007 by Armin Ronacher.
:license: BSD
"""
from difflib import SequenceMatcher
from klaus.utils import escape_html as e
def highlight_line(old_line, new_line):
"""Highlight inline changes in both lines."""
start = 0
limit = min(len(old_line), len(new_line))
while start < limit and old_line[start] == new_line[start]:
start += 1
end = -1
limit -= start
while -end <= limit and old_line[end] == new_line[end]:
end -= 1
end += 1
if start or end:
def do(line, tag):
last = end + len(line)
return b"".join(
[
line[:start],
b"<",
tag,
b">",
line[start:last],
b"</",
tag,
b">",
line[last:],
]
)
old_line = do(old_line, b"del")
new_line = do(new_line, b"ins")
return old_line, new_line
def render_diff(a, b, n=3):
"""Parse the diff an return data for the template."""
actions = []
chunks = []
for group in SequenceMatcher(None, a, b).get_grouped_opcodes(n):
lines = []
def add_line(old_lineno, new_lineno, action, line):
actions.append(action)
lines.append(
{
"old_lineno": old_lineno,
"new_lineno": new_lineno,
"action": action,
"line": line,
"no_newline": not line.endswith(b"\n"),
}
)
chunks.append(lines)
for tag, i1, i2, j1, j2 in group:
if tag == "equal":
for c, line in enumerate(a[i1:i2]):
add_line(i1 + c, j1 + c, "unmod", e(line))
elif tag == "insert":
for c, line in enumerate(b[j1:j2]):
add_line(None, j1 + c, "add", e(line))
elif tag == "delete":
for c, line in enumerate(a[i1:i2]):
add_line(i1 + c, None, "del", e(line))
elif tag == "replace":
for c, line in enumerate(a[i1:i2]):
add_line(i1 + c, None, "del", e(line))
for c, line in enumerate(b[j1:j2]):
add_line(None, j1 + c, "add", e(line))
else:
raise AssertionError("unknown tag %s" % tag)
return actions.count("add"), actions.count("del"), chunks