Skip to content

Commit fdc0fa0

Browse files
committed
Add 'color' arg to difflib.unified_diff.
Fixes gh-133722.
1 parent 5c5b248 commit fdc0fa0

File tree

1 file changed

+25
-6
lines changed

1 file changed

+25
-6
lines changed

Lib/difflib.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,7 @@ def _format_range_unified(start, stop):
10941094
return '{},{}'.format(beginning, length)
10951095

10961096
def unified_diff(a, b, fromfile='', tofile='', fromfiledate='',
1097-
tofiledate='', n=3, lineterm='\n'):
1097+
tofiledate='', n=3, lineterm='\n', color=False):
10981098
r"""
10991099
Compare two sequences of lines; generate the delta as a unified diff.
11001100
@@ -1111,6 +1111,9 @@ def unified_diff(a, b, fromfile='', tofile='', fromfiledate='',
11111111
For inputs that do not have trailing newlines, set the lineterm
11121112
argument to "" so that the output will be uniformly newline free.
11131113
1114+
Set `color` to True to inject ANSI color codes and make the output look
1115+
like what `git diff --color` shows.
1116+
11141117
The unidiff format normally has a header for filenames and modification
11151118
times. Any or all of these may be specified using strings for
11161119
'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.
@@ -1134,20 +1137,34 @@ def unified_diff(a, b, fromfile='', tofile='', fromfiledate='',
11341137
four
11351138
"""
11361139

1140+
# {tag: ANSI color escape code}
1141+
colors = {
1142+
"delete": "\033[31m", # red
1143+
"insert": "\033[32m", # green
1144+
"header": "\033[1m", # bold / increased intensity
1145+
"hunk": "\033[36m", # cyan
1146+
}
1147+
reset = "\033[m"
1148+
11371149
_check_types(a, b, fromfile, tofile, fromfiledate, tofiledate, lineterm)
11381150
started = False
11391151
for group in SequenceMatcher(None,a,b).get_grouped_opcodes(n):
11401152
if not started:
11411153
started = True
11421154
fromdate = '\t{}'.format(fromfiledate) if fromfiledate else ''
11431155
todate = '\t{}'.format(tofiledate) if tofiledate else ''
1144-
yield '--- {}{}{}'.format(fromfile, fromdate, lineterm)
1145-
yield '+++ {}{}{}'.format(tofile, todate, lineterm)
1156+
_line = '--- {}{}{}'.format(fromfile, fromdate, lineterm)
1157+
yield colors["header"] + _line + reset if color else _line
1158+
_line = '+++ {}{}{}'.format(tofile, todate, lineterm)
1159+
yield colors["header"] + _line + reset if color else _line
11461160

11471161
first, last = group[0], group[-1]
11481162
file1_range = _format_range_unified(first[1], last[2])
11491163
file2_range = _format_range_unified(first[3], last[4])
1150-
yield '@@ -{} +{} @@{}'.format(file1_range, file2_range, lineterm)
1164+
_line = '@@ -{} +{} @@{}'.format(file1_range, file2_range, lineterm)
1165+
if color:
1166+
_line = colors["hunk"] + _line + reset
1167+
yield _line
11511168

11521169
for tag, i1, i2, j1, j2 in group:
11531170
if tag == 'equal':
@@ -1156,10 +1173,12 @@ def unified_diff(a, b, fromfile='', tofile='', fromfiledate='',
11561173
continue
11571174
if tag in {'replace', 'delete'}:
11581175
for line in a[i1:i2]:
1159-
yield '-' + line
1176+
_line = '-' + line
1177+
yield colors["delete"] + _line + reset if color else _line
11601178
if tag in {'replace', 'insert'}:
11611179
for line in b[j1:j2]:
1162-
yield '+' + line
1180+
_line = '+' + line
1181+
yield colors["insert"] + _line + reset if color else _line
11631182

11641183

11651184
########################################################################

0 commit comments

Comments
 (0)