Mercurial > hg
comparison contrib/hgdiff @ 1644:e7e6504c4989
Remove duplicate bunidiff code from hgdiff, importing from mdiff.py instead
author | mason@suse.com |
---|---|
date | Sat, 28 Jan 2006 17:16:15 +1300 |
parents | 7da32bb3d1d3 |
children | 0f308690bda8 |
comparison
equal
deleted
inserted
replaced
1643:747c8d03bd29 | 1644:e7e6504c4989 |
---|---|
3 import os, sys, struct, stat | 3 import os, sys, struct, stat |
4 import difflib | 4 import difflib |
5 import re | 5 import re |
6 from optparse import OptionParser | 6 from optparse import OptionParser |
7 from mercurial.bdiff import bdiff, blocks | 7 from mercurial.bdiff import bdiff, blocks |
8 from mercurial.mdiff import bunidiff | |
8 | 9 |
9 VERSION="0.2" | 10 VERSION="0.2" |
10 usage = "usage: %prog [options] file1 file2" | 11 usage = "usage: %prog [options] file1 file2" |
11 parser = OptionParser(usage=usage) | 12 parser = OptionParser(usage=usage) |
12 | 13 |
20 (options, args) = parser.parse_args() | 21 (options, args) = parser.parse_args() |
21 | 22 |
22 if not args: | 23 if not args: |
23 parser.print_help() | 24 parser.print_help() |
24 sys.exit(1) | 25 sys.exit(1) |
25 | |
26 # somewhat self contained replacement for difflib.unified_diff | |
27 # t1 and t2 are the text to be diffed | |
28 # l1 and l2 are the text broken up into lines | |
29 # header1 and header2 are the filenames for the diff output | |
30 # context is the number of context lines | |
31 # showfunc enables diff -p output | |
32 # ignorews ignores all whitespace changes in the diff | |
33 def bunidiff(t1, t2, l1, l2, header1, header2, context=3, showfunc=False, | |
34 ignorews=False): | |
35 def contextend(l, len): | |
36 ret = l + context | |
37 if ret > len: | |
38 ret = len | |
39 return ret | |
40 | |
41 def contextstart(l): | |
42 ret = l - context | |
43 if ret < 0: | |
44 return 0 | |
45 return ret | |
46 | |
47 def yieldhunk(hunk, header): | |
48 if header: | |
49 for x in header: | |
50 yield x | |
51 (astart, a2, bstart, b2, delta) = hunk | |
52 aend = contextend(a2, len(l1)) | |
53 alen = aend - astart | |
54 blen = b2 - bstart + aend - a2 | |
55 | |
56 func = "" | |
57 if showfunc: | |
58 # walk backwards from the start of the context | |
59 # to find a line starting with an alphanumeric char. | |
60 for x in xrange(astart, -1, -1): | |
61 t = l1[x] | |
62 if funcre.match(t): | |
63 func = ' ' + t[:40] | |
64 break | |
65 | |
66 yield "@@ -%d,%d +%d,%d @@%s\n" % (astart + 1, alen, | |
67 bstart + 1, blen, func) | |
68 for x in delta: | |
69 yield x | |
70 for x in xrange(a2, aend): | |
71 yield ' ' + l1[x] | |
72 | |
73 header = [ "--- %s\t\n" % header1, "+++ %s\t\n" % header2 ] | |
74 | |
75 if showfunc: | |
76 funcre = re.compile('\w') | |
77 if ignorews: | |
78 wsre = re.compile('[ \t]') | |
79 | |
80 # bdiff.blocks gives us the matching sequences in the files. The loop | |
81 # below finds the spaces between those matching sequences and translates | |
82 # them into diff output. | |
83 # | |
84 diff = blocks(t1, t2) | |
85 hunk = None | |
86 for i in xrange(len(diff)): | |
87 # The first match is special. | |
88 # we've either found a match starting at line 0 or a match later | |
89 # in the file. If it starts later, old and new below will both be | |
90 # empty and we'll continue to the next match. | |
91 if i > 0: | |
92 s = diff[i-1] | |
93 else: | |
94 s = [0, 0, 0, 0] | |
95 delta = [] | |
96 s1 = diff[i] | |
97 a1 = s[1] | |
98 a2 = s1[0] | |
99 b1 = s[3] | |
100 b2 = s1[2] | |
101 old = l1[a1:a2] | |
102 new = l2[b1:b2] | |
103 | |
104 # bdiff sometimes gives huge matches past eof, this check eats them, | |
105 # and deals with the special first match case described above | |
106 if not old and not new: | |
107 continue | |
108 | |
109 if ignorews: | |
110 wsold = wsre.sub('', "".join(old)) | |
111 wsnew = wsre.sub('', "".join(new)) | |
112 if wsold == wsnew: | |
113 continue | |
114 | |
115 astart = contextstart(a1) | |
116 bstart = contextstart(b1) | |
117 prev = None | |
118 if hunk: | |
119 # join with the previous hunk if it falls inside the context | |
120 if astart < hunk[1] + context + 1: | |
121 prev = hunk | |
122 astart = hunk[1] | |
123 bstart = hunk[3] | |
124 else: | |
125 for x in yieldhunk(hunk, header): | |
126 yield x | |
127 # we only want to yield the header if the files differ, and | |
128 # we only want to yield it once. | |
129 header = None | |
130 if prev: | |
131 # we've joined the previous hunk, record the new ending points. | |
132 hunk[1] = a2 | |
133 hunk[3] = b2 | |
134 delta = hunk[4] | |
135 else: | |
136 # create a new hunk | |
137 hunk = [ astart, a2, bstart, b2, delta ] | |
138 | |
139 delta[len(delta):] = [ ' ' + x for x in l1[astart:a1] ] | |
140 delta[len(delta):] = [ '-' + x for x in old ] | |
141 delta[len(delta):] = [ '+' + x for x in new ] | |
142 | |
143 if hunk: | |
144 for x in yieldhunk(hunk, header): | |
145 yield x | |
146 | 26 |
147 # simple utility function to put all the | 27 # simple utility function to put all the |
148 # files from a directory tree into a dict | 28 # files from a directory tree into a dict |
149 def buildlist(names, top): | 29 def buildlist(names, top): |
150 tlen = len(top) | 30 tlen = len(top) |