Browse Source

Merge pull request #63 from leeor/master

added an argument to control tab expansion
Matthew Wang 7 years ago
parent
commit
a1a33a52b7
2 changed files with 96 additions and 19 deletions
  1. 8
    5
      cdiff.py
  2. 88
    14
      tests/test_cdiff.py

+ 8
- 5
cdiff.py View File

398
 
398
 
399
 class DiffMarker(object):
399
 class DiffMarker(object):
400
 
400
 
401
-    def markup(self, diffs, side_by_side=False, width=0):
401
+    def markup(self, diffs, side_by_side=False, width=0, tab_width=8):
402
         """Returns a generator"""
402
         """Returns a generator"""
403
         if side_by_side:
403
         if side_by_side:
404
             for diff in diffs:
404
             for diff in diffs:
405
-                for line in self._markup_side_by_side(diff, width):
405
+                for line in self._markup_side_by_side(diff, width, tab_width):
406
                     yield line
406
                     yield line
407
         else:
407
         else:
408
             for diff in diffs:
408
             for diff in diffs:
442
                 else:
442
                 else:
443
                     yield self._markup_common(' ' + old[1])
443
                     yield self._markup_common(' ' + old[1])
444
 
444
 
445
-    def _markup_side_by_side(self, diff, width):
445
+    def _markup_side_by_side(self, diff, width, tab_width):
446
         """Returns a generator"""
446
         """Returns a generator"""
447
         wrap_char = colorize('>', 'lightmagenta')
447
         wrap_char = colorize('>', 'lightmagenta')
448
 
448
 
449
         def _normalize(line):
449
         def _normalize(line):
450
             return line.replace(
450
             return line.replace(
451
-                '\t', ' ' * 8).replace('\n', '').replace('\r', '')
451
+                '\t', ' ' * tab_width).replace('\n', '').replace('\r', '')
452
 
452
 
453
         def _fit_with_marker(text, markup_fn, width, pad=False):
453
         def _fit_with_marker(text, markup_fn, width, pad=False):
454
             """Wrap or pad input pure text, then markup"""
454
             """Wrap or pad input pure text, then markup"""
642
     diffs = DiffParser(stream).get_diff_generator()
642
     diffs = DiffParser(stream).get_diff_generator()
643
     marker = DiffMarker()
643
     marker = DiffMarker()
644
     color_diff = marker.markup(diffs, side_by_side=opts.side_by_side,
644
     color_diff = marker.markup(diffs, side_by_side=opts.side_by_side,
645
-                               width=opts.width)
645
+                               width=opts.width, tab_width=opts.tab_width)
646
 
646
 
647
     for line in color_diff:
647
     for line in color_diff:
648
         pager.stdin.write(line.encode('utf-8'))
648
         pager.stdin.write(line.encode('utf-8'))
751
     parser.add_option(
751
     parser.add_option(
752
         '-c', '--color', default='auto', metavar='M',
752
         '-c', '--color', default='auto', metavar='M',
753
         help="""colorize mode 'auto' (default), 'always', or 'never'""")
753
         help="""colorize mode 'auto' (default), 'always', or 'never'""")
754
+    parser.add_option(
755
+        '-t', '--tab-width', type='int', default=8, metavar='N',
756
+        help="""convert tab characters to this many spcaes (default: 8)""")
754
 
757
 
755
     # Hack: use OptionGroup text for extra help message after option list
758
     # Hack: use OptionGroup text for extra help message after option list
756
     option_group = OptionGroup(
759
     option_group = OptionGroup(

+ 88
- 14
tests/test_cdiff.py View File

108
             --- old
108
             --- old
109
             +++ new
109
             +++ new
110
             hunk header
110
             hunk header
111
-            @@ -1,4 +1,4 @@
111
+            @@ -1,5 +1,5 @@
112
             -hhello
112
             -hhello
113
             +helloo
113
             +helloo
114
             +spammm
114
             +spammm
115
              world
115
              world
116
             -garb
116
             -garb
117
             -Again
117
             -Again
118
+            -	tabbed
118
             +again
119
             +again
120
+            + spaced
119
         """
121
         """
120
 
122
 
121
-        hunk = cdiff.Hunk(['hunk header\n'], '@@ -1,4 +1,4 @@\n',
122
-                          (1, 4), (1, 4))
123
+        hunk = cdiff.Hunk(['hunk header\n'], '@@ -1,5 +1,5 @@\n',
124
+                          (1, 5), (1, 5))
123
         hunk.append(('-', 'hhello\n'))
125
         hunk.append(('-', 'hhello\n'))
124
         hunk.append(('+', 'helloo\n'))
126
         hunk.append(('+', 'helloo\n'))
125
         hunk.append(('+', 'spammm\n'))
127
         hunk.append(('+', 'spammm\n'))
126
         hunk.append((' ', 'world\n'))
128
         hunk.append((' ', 'world\n'))
127
         hunk.append(('-', 'garb\n'))
129
         hunk.append(('-', 'garb\n'))
128
         hunk.append(('-', 'Again\n'))
130
         hunk.append(('-', 'Again\n'))
131
+        hunk.append(('-', '	tabbed\n'))
129
         hunk.append(('+', 'again\n'))
132
         hunk.append(('+', 'again\n'))
133
+        hunk.append(('+', ' spaced\n'))
130
         diff = cdiff.UnifiedDiff(
134
         diff = cdiff.UnifiedDiff(
131
             ['header\n'], '--- old\n', '+++ new\n', [hunk])
135
             ['header\n'], '--- old\n', '+++ new\n', [hunk])
132
         return diff
136
         return diff
210
         diff = self._init_diff()
214
         diff = self._init_diff()
211
         marker = cdiff.DiffMarker()
215
         marker = cdiff.DiffMarker()
212
 
216
 
213
-        out = list(marker._markup_side_by_side(diff, 7))
214
-        self.assertEqual(len(out), 10)
217
+        out = list(marker._markup_side_by_side(diff, 7, 8))
218
+        self.assertEqual(len(out), 11)
215
 
219
 
216
         sys.stdout.write('\n')
220
         sys.stdout.write('\n')
217
         for markup in out:
221
         for markup in out:
221
         self.assertEqual(out[1], '\x1b[33m--- old\n\x1b[0m')
225
         self.assertEqual(out[1], '\x1b[33m--- old\n\x1b[0m')
222
         self.assertEqual(out[2], '\x1b[33m+++ new\n\x1b[0m')
226
         self.assertEqual(out[2], '\x1b[33m+++ new\n\x1b[0m')
223
         self.assertEqual(out[3], '\x1b[1;36mhunk header\n\x1b[0m')
227
         self.assertEqual(out[3], '\x1b[1;36mhunk header\n\x1b[0m')
224
-        self.assertEqual(out[4], '\x1b[1;34m@@ -1,4 +1,4 @@\n\x1b[0m')
228
+        self.assertEqual(out[4], '\x1b[1;34m@@ -1,5 +1,5 @@\n\x1b[0m')
225
         self.assertEqual(
229
         self.assertEqual(
226
             out[5],
230
             out[5],
227
             '\x1b[33m1\x1b[0m '
231
             '\x1b[33m1\x1b[0m '
252
             '\x1b[31m\x1b[4m\x1b[31mA\x1b[0m\x1b[31mgain\x1b[0m   '
256
             '\x1b[31m\x1b[4m\x1b[31mA\x1b[0m\x1b[31mgain\x1b[0m   '
253
             '\x1b[0m\x1b[33m4\x1b[0m '
257
             '\x1b[0m\x1b[33m4\x1b[0m '
254
             '\x1b[32m\x1b[4m\x1b[32ma\x1b[0m\x1b[32mgain\x1b[0m\n')
258
             '\x1b[32m\x1b[4m\x1b[32ma\x1b[0m\x1b[32mgain\x1b[0m\n')
259
+        self.assertEqual(
260
+            out[10],
261
+            '\x1b[33m5\x1b[0m '
262
+            '\x1b[31m\x1b[7m\x1b[31m      \x1b[0m\x1b[1;35m>\x1b[0m '
263
+            '\x1b[0m\x1b[33m5\x1b[0m '
264
+            '\x1b[32m\x1b[7m\x1b[32m spaced\x1b[0m\n')
255
 
265
 
256
     # This test is not valid anymore
266
     # This test is not valid anymore
257
     def __test_markup_side_by_side_neg_width(self):
267
     def __test_markup_side_by_side_neg_width(self):
258
         diff = self._init_diff()
268
         diff = self._init_diff()
259
         marker = cdiff.DiffMarker()
269
         marker = cdiff.DiffMarker()
260
-        out = list(marker._markup_side_by_side(diff, -1))
261
-        self.assertEqual(len(out), 10)
270
+        out = list(marker._markup_side_by_side(diff, -1, 8))
271
+        self.assertEqual(len(out), 11)
262
 
272
 
263
         self.assertEqual(out[0], '\x1b[36mheader\n\x1b[0m')
273
         self.assertEqual(out[0], '\x1b[36mheader\n\x1b[0m')
264
         self.assertEqual(out[1], '\x1b[33m--- old\n\x1b[0m')
274
         self.assertEqual(out[1], '\x1b[33m--- old\n\x1b[0m')
301
     def test_markup_side_by_side_off_by_one(self):
311
     def test_markup_side_by_side_off_by_one(self):
302
         diff = self._init_diff()
312
         diff = self._init_diff()
303
         marker = cdiff.DiffMarker()
313
         marker = cdiff.DiffMarker()
304
-        out = list(marker._markup_side_by_side(diff, 6))
305
-        self.assertEqual(len(out), 10)
314
+        out = list(marker._markup_side_by_side(diff, 6, 8))
315
+        self.assertEqual(len(out), 11)
306
 
316
 
307
         sys.stdout.write('\n')
317
         sys.stdout.write('\n')
308
         for markup in out:
318
         for markup in out:
312
         self.assertEqual(out[1], '\x1b[33m--- old\n\x1b[0m')
322
         self.assertEqual(out[1], '\x1b[33m--- old\n\x1b[0m')
313
         self.assertEqual(out[2], '\x1b[33m+++ new\n\x1b[0m')
323
         self.assertEqual(out[2], '\x1b[33m+++ new\n\x1b[0m')
314
         self.assertEqual(out[3], '\x1b[1;36mhunk header\n\x1b[0m')
324
         self.assertEqual(out[3], '\x1b[1;36mhunk header\n\x1b[0m')
315
-        self.assertEqual(out[4], '\x1b[1;34m@@ -1,4 +1,4 @@\n\x1b[0m')
325
+        self.assertEqual(out[4], '\x1b[1;34m@@ -1,5 +1,5 @@\n\x1b[0m')
316
         self.assertEqual(
326
         self.assertEqual(
317
             out[5],
327
             out[5],
318
             '\x1b[33m1\x1b[0m '
328
             '\x1b[33m1\x1b[0m '
342
             '\x1b[31m\x1b[4m\x1b[31mA\x1b[0m\x1b[31mgain\x1b[0m  '
352
             '\x1b[31m\x1b[4m\x1b[31mA\x1b[0m\x1b[31mgain\x1b[0m  '
343
             '\x1b[0m\x1b[33m4\x1b[0m '
353
             '\x1b[0m\x1b[33m4\x1b[0m '
344
             '\x1b[32m\x1b[4m\x1b[32ma\x1b[0m\x1b[32mgain\x1b[0m\n')
354
             '\x1b[32m\x1b[4m\x1b[32ma\x1b[0m\x1b[32mgain\x1b[0m\n')
355
+        self.assertEqual(
356
+            out[10],
357
+            '\x1b[33m5\x1b[0m '
358
+            '\x1b[31m\x1b[7m\x1b[31m     \x1b[0m\x1b[1;35m>\x1b[0m '
359
+            '\x1b[0m\x1b[33m5\x1b[0m '
360
+            '\x1b[32m\x1b[7m\x1b[32m spac\x1b[0m\x1b[1;35m>\x1b[0m\n')
345
 
361
 
346
     def test_markup_side_by_side_wrapped(self):
362
     def test_markup_side_by_side_wrapped(self):
347
         diff = self._init_diff()
363
         diff = self._init_diff()
348
         marker = cdiff.DiffMarker()
364
         marker = cdiff.DiffMarker()
349
-        out = list(marker._markup_side_by_side(diff, 5))
350
-        self.assertEqual(len(out), 10)
365
+        out = list(marker._markup_side_by_side(diff, 5, 8))
366
+        self.assertEqual(len(out), 11)
351
 
367
 
352
         sys.stdout.write('\n')
368
         sys.stdout.write('\n')
353
         for markup in out:
369
         for markup in out:
357
         self.assertEqual(out[1], '\x1b[33m--- old\n\x1b[0m')
373
         self.assertEqual(out[1], '\x1b[33m--- old\n\x1b[0m')
358
         self.assertEqual(out[2], '\x1b[33m+++ new\n\x1b[0m')
374
         self.assertEqual(out[2], '\x1b[33m+++ new\n\x1b[0m')
359
         self.assertEqual(out[3], '\x1b[1;36mhunk header\n\x1b[0m')
375
         self.assertEqual(out[3], '\x1b[1;36mhunk header\n\x1b[0m')
360
-        self.assertEqual(out[4], '\x1b[1;34m@@ -1,4 +1,4 @@\n\x1b[0m')
376
+        self.assertEqual(out[4], '\x1b[1;34m@@ -1,5 +1,5 @@\n\x1b[0m')
361
         self.assertEqual(
377
         self.assertEqual(
362
             out[5],
378
             out[5],
363
             '\x1b[33m1\x1b[0m '
379
             '\x1b[33m1\x1b[0m '
388
             '\x1b[31m\x1b[4m\x1b[31mA\x1b[0m\x1b[31mgain\x1b[0m '
404
             '\x1b[31m\x1b[4m\x1b[31mA\x1b[0m\x1b[31mgain\x1b[0m '
389
             '\x1b[0m\x1b[33m4\x1b[0m '
405
             '\x1b[0m\x1b[33m4\x1b[0m '
390
             '\x1b[32m\x1b[4m\x1b[32ma\x1b[0m\x1b[32mgain\x1b[0m\n')
406
             '\x1b[32m\x1b[4m\x1b[32ma\x1b[0m\x1b[32mgain\x1b[0m\n')
407
+        self.assertEqual(
408
+            out[10],
409
+            '\x1b[33m5\x1b[0m '
410
+            '\x1b[31m\x1b[7m\x1b[31m    \x1b[0m\x1b[1;35m>\x1b[0m '
411
+            '\x1b[0m\x1b[33m5\x1b[0m '
412
+            '\x1b[32m\x1b[7m\x1b[32m spa\x1b[0m\x1b[1;35m>\x1b[0m\n')
413
+
414
+    def test_markup_side_by_side_tabbed(self):
415
+        diff = self._init_diff()
416
+        marker = cdiff.DiffMarker()
417
+        out = list(marker._markup_side_by_side(diff, 8, 2))
418
+        self.assertEqual(len(out), 11)
419
+
420
+        sys.stdout.write('\n')
421
+        for markup in out:
422
+            sys.stdout.write(markup)
423
+
424
+        self.assertEqual(out[0], '\x1b[36mheader\n\x1b[0m')
425
+        self.assertEqual(out[1], '\x1b[33m--- old\n\x1b[0m')
426
+        self.assertEqual(out[2], '\x1b[33m+++ new\n\x1b[0m')
427
+        self.assertEqual(out[3], '\x1b[1;36mhunk header\n\x1b[0m')
428
+        self.assertEqual(out[4], '\x1b[1;34m@@ -1,5 +1,5 @@\n\x1b[0m')
429
+        self.assertEqual(
430
+            out[5],
431
+            '\x1b[33m1\x1b[0m '
432
+            '\x1b[31m\x1b[7m\x1b[31mh\x1b[0m\x1b[31mhello\x1b[0m   '
433
+            '\x1b[0m\x1b[33m1\x1b[0m '
434
+            '\x1b[32mhello\x1b[7m\x1b[32mo\x1b[0m\x1b[32m\x1b[0m\n')
435
+        self.assertEqual(
436
+            out[6],
437
+            '\x1b[33m '
438
+            '\x1b[0m          '
439
+            '\x1b[0m\x1b[33m2\x1b[0m '
440
+            '\x1b[32mspammm\x1b[0m\n')
441
+        self.assertEqual(
442
+            out[7],
443
+            '\x1b[33m2\x1b[0m '
444
+            '\x1b[0mworld\x1b[0m    '
445
+            '\x1b[0m\x1b[33m3\x1b[0m '
446
+            '\x1b[0mworld\x1b[0m\n')
447
+        self.assertEqual(
448
+            out[8],
449
+            '\x1b[33m3\x1b[0m '
450
+            '\x1b[1;31mgarb\x1b[0m '
451
+            '\x1b[0m\x1b[33m '
452
+            '\x1b[0m \n')
453
+        self.assertEqual(
454
+            out[9],
455
+            '\x1b[33m4\x1b[0m '
456
+            '\x1b[31m\x1b[4m\x1b[31mA\x1b[0m\x1b[31mgain\x1b[0m    '
457
+            '\x1b[0m\x1b[33m4\x1b[0m '
458
+            '\x1b[32m\x1b[4m\x1b[32ma\x1b[0m\x1b[32mgain\x1b[0m\n')
459
+        self.assertEqual(
460
+            out[10],
461
+            '\x1b[33m5\x1b[0m '
462
+            '\x1b[31m\x1b[7m\x1b[31m  tabbed\x1b[0m '
463
+            '\x1b[0m\x1b[33m5\x1b[0m '
464
+            '\x1b[32m\x1b[7m\x1b[32m spaced\x1b[0m\x1b[32m\x1b[0m\n')
391
 
465
 
392
 
466
 
393
 class UnifiedDiffTest(unittest.TestCase):
467
 class UnifiedDiffTest(unittest.TestCase):