comparison diff-colorize.py @ 18:83d58ccc70bf

Interleave adjacent runs of consecutive old and new lines into alternating old and new lines.
author Peter Hosey <hg@boredzo.org>
date Wed, 05 Jan 2011 06:56:01 -0800
parents 54a209909531
children b709258a2fc2
comparison
equal deleted inserted replaced
17:54a209909531 18:83d58ccc70bf
38 * DIFF_NEW_MODE_COLOR (lines starting with "new mode"; these only appear in git-style diffs) 38 * DIFF_NEW_MODE_COLOR (lines starting with "new mode"; these only appear in git-style diffs)
39 * DIFF_REMOVED_COLOR (lines starting with "-") 39 * DIFF_REMOVED_COLOR (lines starting with "-")
40 * DIFF_ADDED_COLOR (lines starting with "+") 40 * DIFF_ADDED_COLOR (lines starting with "+")
41 * DIFF_HUNK_START_COLOR (lines starting with "@@") 41 * DIFF_HUNK_START_COLOR (lines starting with "@@")
42 """.strip() 42 """.strip()
43
44 def interleave(*sequences):
45 "Generator that yields one object from each sequence in turn."
46
47 def zip_pad(*iterables, **kw):
48 "Downloaded from http://code.activestate.com/recipes/497007/"
49 from itertools import izip, chain
50 if kw:
51 assert len(kw) == 1
52 pad = kw["pad"]
53 else:
54 pad = None
55 done = [len(iterables)-1]
56 def pad_iter():
57 if not done[0]:
58 return
59 done[0] -= 1
60 while 1:
61 yield pad
62 iterables = [chain(seq, pad_iter()) for seq in iterables]
63 return izip(*iterables)
64
65 for objects in zip_pad(*sequences):
66 for obj in objects:
67 if obj is not None:
68 yield obj
43 69
44 # Everything in the unified diff format is identified by a prefix. The prefixes are: 70 # Everything in the unified diff format is identified by a prefix. The prefixes are:
45 # 'Index: ': File marker (unified diff) 71 # 'Index: ': File marker (unified diff)
46 # 'diff --git': File marker (git-style diff) 72 # 'diff --git': File marker (git-style diff)
47 # 'old mode': File permissions mode before change 73 # 'old mode': File permissions mode before change
125 if __name__ == "__main__": 151 if __name__ == "__main__":
126 if sys.stdin.isatty(): 152 if sys.stdin.isatty():
127 # Standard input is a TTY, meaning that the user ran 'diff-colorize' at the shell prompt, without redirecting anything into it. Print usage info and exit. 153 # Standard input is a TTY, meaning that the user ran 'diff-colorize' at the shell prompt, without redirecting anything into it. Print usage info and exit.
128 sys.exit(USAGE) 154 sys.exit(USAGE)
129 155
156 # Buffers to support interleaving old and new lines that were contiguous runs.
157 buffer_old = [] # '-' lines
158 buffer_new = [] # '+' lines
159
130 for line in fileinput.input(): 160 for line in fileinput.input():
161 if line.startswith('-') and not line.startswith('---'):
162 buffer_old.append(line)
163 continue
164 elif line.startswith('+') and not line.startswith('+++'):
165 buffer_new.append(line)
166 continue
167 else:
168 # Flush the buffers, interleaving the lines.
169 for buffered_line in interleave(buffer_old, buffer_new):
170 prefix = '-' if buffered_line.startswith('-') else '+'
171 buffered_line = buffered_line[len(prefix):]
172
173 sys.stdout.write(prefixes[prefix])
174 sys.stdout.write(buffered_line)
175 sys.stdout.write(RESET_FORMAT)
176
177 del buffer_old[:]
178 del buffer_new[:]
179
131 for prefix_to_test in prefixes: 180 for prefix_to_test in prefixes:
132 if line.startswith(prefix_to_test): 181 if line.startswith(prefix_to_test):
133 sys.stdout.write(prefixes[prefix_to_test]) 182 sys.stdout.write(prefixes[prefix_to_test])
134 line = line[len(prefix_to_test):] 183 line = line[len(prefix_to_test):]
135 184