浏览代码

support line number display; remove -n option

Matthew Wang 11 年前
父节点
当前提交
ebbba92673
共有 2 个文件被更改,包括 64 次插入27 次删除
  1. 1
    0
      Makefile
  2. 63
    27
      src/cdiff.py

+ 1
- 0
Makefile 查看文件

5
 dogfood:
5
 dogfood:
6
 	git diff | src/cdiff.py
6
 	git diff | src/cdiff.py
7
 	git diff | src/cdiff.py -s
7
 	git diff | src/cdiff.py -s
8
+	git diff | src/cdiff.py -s -w 100
8
 
9
 
9
 test: single-udiff multi-udiff
10
 test: single-udiff multi-udiff
10
 
11
 

+ 63
- 27
src/cdiff.py 查看文件

33
 
33
 
34
 class Hunk(object):
34
 class Hunk(object):
35
 
35
 
36
-    def __init__(self, hunk_header):
36
+    def __init__(self, hunk_header, old_addr, new_addr):
37
         self._hunk_header = hunk_header
37
         self._hunk_header = hunk_header
38
-        self._hunk_list = []   # 2-element group (attr, line)
38
+        self._old_addr = old_addr   # tuple (start, offset)
39
+        self._new_addr = new_addr   # tuple group (start, offset)
40
+        self._hunk_list = []        # list of tuple (attr, line)
39
 
41
 
40
     def get_header(self):
42
     def get_header(self):
41
         return self._hunk_header
43
         return self._hunk_header
42
 
44
 
45
+    def get_old_addr(self):
46
+        return self._old_addr
47
+
48
+    def get_new_addr(self):
49
+        return self._new_addr
50
+
43
     def append(self, attr, line):
51
     def append(self, attr, line):
44
         """attr: '-': old, '+': new, ' ': common"""
52
         """attr: '-': old, '+': new, ' ': common"""
45
         self._hunk_list.append((attr, line))
53
         self._hunk_list.append((attr, line))
119
                 else:
127
                 else:
120
                     yield self._markup_common(' ' + old[1])
128
                     yield self._markup_common(' ' + old[1])
121
 
129
 
122
-    def markup_side_by_side(self, show_number, width):
130
+    def markup_side_by_side(self, width):
123
         """width of 0 means infinite width, None means auto detect. Returns a
131
         """width of 0 means infinite width, None means auto detect. Returns a
124
         generator
132
         generator
125
         """
133
         """
126
         def _normalize(line):
134
         def _normalize(line):
127
             return line.replace('\t', ' ' * 8).replace('\n', '')
135
             return line.replace('\t', ' ' * 8).replace('\n', '')
128
 
136
 
129
-        def _fit_width(markup, width):
137
+        def _fit_width(markup, width, pad=False):
130
             """str len does not count correctly if left column contains ansi
138
             """str len does not count correctly if left column contains ansi
131
-            color code
139
+            color code.  Only left side need to set `pad`
132
             """
140
             """
133
             line = re.sub(r'\x1b\[(1;)?\d{1,2}m', '', markup)
141
             line = re.sub(r'\x1b\[(1;)?\d{1,2}m', '', markup)
134
-            if len(line) < width:
135
-                pad = width - len(line)
136
-                return '%s%*s' % (markup, pad, '')
142
+            if pad and len(line) < width:
143
+                pad_len = width - len(line)
144
+                return '%s%*s' % (markup, pad_len, '')
137
             else:
145
             else:
138
                 # TODO
146
                 # TODO
139
                 return markup
147
                 return markup
140
 
148
 
141
-        width = 80
142
-        line_fmt = '%%s %s %%s\n' % colorize('|', 'lightyellow')
143
-
149
+        # Setup line width and number width
150
+        if not width: width = 80
151
+        (start, offset) = self._hunks[-1].get_old_addr()
152
+        max1 = start + offset - 1
153
+        (start, offset) = self._hunks[-1].get_new_addr()
154
+        max2 = start + offset - 1
155
+        num_width = max(len(str(max1)), len(str(max2)))
156
+        left_num_fmt = colorize('%%(left_num)%ds' % num_width, 'yellow')
157
+        right_num_fmt = colorize('%%(right_num)%ds' % num_width, 'yellow')
158
+        line_fmt = left_num_fmt + ' %(left)s ' + right_num_fmt + \
159
+                ' %(right)s\n'
160
+
161
+        # yield header, old path and new path
144
         for line in self._headers:
162
         for line in self._headers:
145
             yield self._markup_header(line)
163
             yield self._markup_header(line)
146
-
147
         yield self._markup_old_path(self._old_path)
164
         yield self._markup_old_path(self._old_path)
148
         yield self._markup_new_path(self._new_path)
165
         yield self._markup_new_path(self._new_path)
149
 
166
 
167
+        # yield hunks
150
         for hunk in self._hunks:
168
         for hunk in self._hunks:
151
             yield self._markup_hunk_header(hunk.get_header())
169
             yield self._markup_hunk_header(hunk.get_header())
152
             for old, new, changed in hunk.mdiff():
170
             for old, new, changed in hunk.mdiff():
171
+                if old[0]:
172
+                    left_num = str(hunk.get_old_addr()[0] + int(old[0]) - 1)
173
+                else:
174
+                    left_num = ' '
175
+
176
+                if new[0]:
177
+                    right_num = str(hunk.get_new_addr()[0] + int(new[0]) - 1)
178
+                else:
179
+                    right_num = ' '
180
+
153
                 left = _normalize(old[1])
181
                 left = _normalize(old[1])
154
                 right = _normalize(new[1])
182
                 right = _normalize(new[1])
183
+
155
                 if changed:
184
                 if changed:
156
                     if not old[0]:
185
                     if not old[0]:
157
-                        left = '%*s' % (width, '')
186
+                        left = '%*s' % (width, ' ')
158
                         right = right.lstrip('\x00+').rstrip('\x01')
187
                         right = right.lstrip('\x00+').rstrip('\x01')
159
                         right = _fit_width(self._markup_new(right), width)
188
                         right = _fit_width(self._markup_new(right), width)
160
-                        yield line_fmt % (left, right)
161
                     elif not new[0]:
189
                     elif not new[0]:
162
                         left = left.lstrip('\x00-').rstrip('\x01')
190
                         left = left.lstrip('\x00-').rstrip('\x01')
163
                         left = _fit_width(self._markup_old(left), width)
191
                         left = _fit_width(self._markup_old(left), width)
164
-                        yield line_fmt % (left, '')
192
+                        right = ''
165
                     else:
193
                     else:
166
-                        left = _fit_width(self._markup_old_mix(left), width)
194
+                        left = _fit_width(self._markup_old_mix(left), width, 1)
167
                         right = _fit_width(self._markup_new_mix(right), width)
195
                         right = _fit_width(self._markup_new_mix(right), width)
168
-                        yield line_fmt % (left, right)
169
                 else:
196
                 else:
170
-                    left = _fit_width(self._markup_common(left), width)
197
+                    left = _fit_width(self._markup_common(left), width, 1)
171
                     right = _fit_width(self._markup_common(right), width)
198
                     right = _fit_width(self._markup_common(right), width)
172
-                    yield line_fmt % (left, right)
199
+                yield line_fmt % {
200
+                    'left_num': left_num,
201
+                    'left': left,
202
+                    'right_num': right_num,
203
+                    'right': right
204
+                }
173
 
205
 
174
     def _markup_header(self, line):
206
     def _markup_header(self, line):
175
         return colorize(line, 'cyan')
207
         return colorize(line, 'cyan')
324
                     hunks.append(hunk)
356
                     hunks.append(hunk)
325
                     hunk = None
357
                     hunk = None
326
                 else:
358
                 else:
327
-                    hunk = Hunk(stream.pop(0))
359
+                    # @@ -3,7 +3,6 @@
360
+                    hunk_header = stream.pop(0)
361
+                    a = hunk_header.split()[1].split(',')   # -3 7
362
+                    old_addr = (int(a[0][1:]), int(a[1]))
363
+                    b = hunk_header.split()[2].split(',')   # +3 6
364
+                    new_addr = (int(b[0][1:]), int(b[1]))
365
+                    hunk = Hunk(hunk_header, old_addr, new_addr)
328
 
366
 
329
             elif Udiff.is_old(stream[0]) or Udiff.is_new(stream[0]) or \
367
             elif Udiff.is_old(stream[0]) or Udiff.is_new(stream[0]) or \
330
                     Udiff.is_common(stream[0]):
368
                     Udiff.is_common(stream[0]):
361
     def __init__(self, stream):
399
     def __init__(self, stream):
362
         self._diffs = DiffParser(stream).get_diffs()
400
         self._diffs = DiffParser(stream).get_diffs()
363
 
401
 
364
-    def markup(self, side_by_side=False, show_number=False, width=0):
402
+    def markup(self, side_by_side=False, width=0):
365
         """Returns a generator"""
403
         """Returns a generator"""
366
         if side_by_side:
404
         if side_by_side:
367
-            return self._markup_side_by_side(show_number, width)
405
+            return self._markup_side_by_side(width)
368
         else:
406
         else:
369
             return self._markup_traditional()
407
             return self._markup_traditional()
370
 
408
 
373
             for line in diff.markup_traditional():
411
             for line in diff.markup_traditional():
374
                 yield line
412
                 yield line
375
 
413
 
376
-    def _markup_side_by_side(self, show_number, width):
414
+    def _markup_side_by_side(self, width):
377
         for diff in self._diffs:
415
         for diff in self._diffs:
378
-            for line in diff.markup_side_by_side(show_number, width):
416
+            for line in diff.markup_side_by_side(width):
379
                 yield line
417
                 yield line
380
 
418
 
381
 
419
 
392
     parser = optparse.OptionParser(usage)
430
     parser = optparse.OptionParser(usage)
393
     parser.add_option('-s', '--side-by-side', action='store_true',
431
     parser.add_option('-s', '--side-by-side', action='store_true',
394
             help=('show in side-by-side mode'))
432
             help=('show in side-by-side mode'))
395
-    parser.add_option('-n', '--number', action='store_true',
396
-            help='show line number')
397
     parser.add_option('-w', '--width', type='int', default=None,
433
     parser.add_option('-w', '--width', type='int', default=None,
398
             help='set line width (side-by-side mode only)')
434
             help='set line width (side-by-side mode only)')
399
     opts, args = parser.parse_args()
435
     opts, args = parser.parse_args()
417
     if sys.stdout.isatty():
453
     if sys.stdout.isatty():
418
         markup = DiffMarkup(stream)
454
         markup = DiffMarkup(stream)
419
         color_diff = markup.markup(side_by_side=opts.side_by_side,
455
         color_diff = markup.markup(side_by_side=opts.side_by_side,
420
-                show_number=opts.number, width=opts.width)
456
+                width=opts.width)
421
 
457
 
422
         # args stolen fron git source: github.com/git/git/blob/master/pager.c
458
         # args stolen fron git source: github.com/git/git/blob/master/pager.c
423
         pager = subprocess.Popen(['less', '-FRSXK'],
459
         pager = subprocess.Popen(['less', '-FRSXK'],