Просмотр исходного кода

support line number display; remove -n option

Matthew Wang 11 лет назад
Родитель
Сommit
ebbba92673
2 измененных файлов: 64 добавлений и 27 удалений
  1. 1
    0
      Makefile
  2. 63
    27
      src/cdiff.py

+ 1
- 0
Makefile Просмотреть файл

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

+ 63
- 27
src/cdiff.py Просмотреть файл

@@ -33,13 +33,21 @@ def colorize(text, start_color, end_color='reset'):
33 33
 
34 34
 class Hunk(object):
35 35
 
36
-    def __init__(self, hunk_header):
36
+    def __init__(self, hunk_header, old_addr, new_addr):
37 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 42
     def get_header(self):
41 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 51
     def append(self, attr, line):
44 52
         """attr: '-': old, '+': new, ' ': common"""
45 53
         self._hunk_list.append((attr, line))
@@ -119,57 +127,81 @@ class Diff(object):
119 127
                 else:
120 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 131
         """width of 0 means infinite width, None means auto detect. Returns a
124 132
         generator
125 133
         """
126 134
         def _normalize(line):
127 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 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 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 145
             else:
138 146
                 # TODO
139 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 162
         for line in self._headers:
145 163
             yield self._markup_header(line)
146
-
147 164
         yield self._markup_old_path(self._old_path)
148 165
         yield self._markup_new_path(self._new_path)
149 166
 
167
+        # yield hunks
150 168
         for hunk in self._hunks:
151 169
             yield self._markup_hunk_header(hunk.get_header())
152 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 181
                 left = _normalize(old[1])
154 182
                 right = _normalize(new[1])
183
+
155 184
                 if changed:
156 185
                     if not old[0]:
157
-                        left = '%*s' % (width, '')
186
+                        left = '%*s' % (width, ' ')
158 187
                         right = right.lstrip('\x00+').rstrip('\x01')
159 188
                         right = _fit_width(self._markup_new(right), width)
160
-                        yield line_fmt % (left, right)
161 189
                     elif not new[0]:
162 190
                         left = left.lstrip('\x00-').rstrip('\x01')
163 191
                         left = _fit_width(self._markup_old(left), width)
164
-                        yield line_fmt % (left, '')
192
+                        right = ''
165 193
                     else:
166
-                        left = _fit_width(self._markup_old_mix(left), width)
194
+                        left = _fit_width(self._markup_old_mix(left), width, 1)
167 195
                         right = _fit_width(self._markup_new_mix(right), width)
168
-                        yield line_fmt % (left, right)
169 196
                 else:
170
-                    left = _fit_width(self._markup_common(left), width)
197
+                    left = _fit_width(self._markup_common(left), width, 1)
171 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 206
     def _markup_header(self, line):
175 207
         return colorize(line, 'cyan')
@@ -324,7 +356,13 @@ class DiffParser(object):
324 356
                     hunks.append(hunk)
325 357
                     hunk = None
326 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 367
             elif Udiff.is_old(stream[0]) or Udiff.is_new(stream[0]) or \
330 368
                     Udiff.is_common(stream[0]):
@@ -361,10 +399,10 @@ class DiffMarkup(object):
361 399
     def __init__(self, stream):
362 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 403
         """Returns a generator"""
366 404
         if side_by_side:
367
-            return self._markup_side_by_side(show_number, width)
405
+            return self._markup_side_by_side(width)
368 406
         else:
369 407
             return self._markup_traditional()
370 408
 
@@ -373,9 +411,9 @@ class DiffMarkup(object):
373 411
             for line in diff.markup_traditional():
374 412
                 yield line
375 413
 
376
-    def _markup_side_by_side(self, show_number, width):
414
+    def _markup_side_by_side(self, width):
377 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 417
                 yield line
380 418
 
381 419
 
@@ -392,8 +430,6 @@ if __name__ == '__main__':
392 430
     parser = optparse.OptionParser(usage)
393 431
     parser.add_option('-s', '--side-by-side', action='store_true',
394 432
             help=('show in side-by-side mode'))
395
-    parser.add_option('-n', '--number', action='store_true',
396
-            help='show line number')
397 433
     parser.add_option('-w', '--width', type='int', default=None,
398 434
             help='set line width (side-by-side mode only)')
399 435
     opts, args = parser.parse_args()
@@ -417,7 +453,7 @@ if __name__ == '__main__':
417 453
     if sys.stdout.isatty():
418 454
         markup = DiffMarkup(stream)
419 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 458
         # args stolen fron git source: github.com/git/git/blob/master/pager.c
423 459
         pager = subprocess.Popen(['less', '-FRSXK'],