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,11 +398,11 @@ class DiffParser(object):
398 398
 
399 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 402
         """Returns a generator"""
403 403
         if side_by_side:
404 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 406
                     yield line
407 407
         else:
408 408
             for diff in diffs:
@@ -442,13 +442,13 @@ class DiffMarker(object):
442 442
                 else:
443 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 446
         """Returns a generator"""
447 447
         wrap_char = colorize('>', 'lightmagenta')
448 448
 
449 449
         def _normalize(line):
450 450
             return line.replace(
451
-                '\t', ' ' * 8).replace('\n', '').replace('\r', '')
451
+                '\t', ' ' * tab_width).replace('\n', '').replace('\r', '')
452 452
 
453 453
         def _fit_with_marker(text, markup_fn, width, pad=False):
454 454
             """Wrap or pad input pure text, then markup"""
@@ -642,7 +642,7 @@ def markup_to_pager(stream, opts):
642 642
     diffs = DiffParser(stream).get_diff_generator()
643 643
     marker = DiffMarker()
644 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 647
     for line in color_diff:
648 648
         pager.stdin.write(line.encode('utf-8'))
@@ -751,6 +751,9 @@ def main():
751 751
     parser.add_option(
752 752
         '-c', '--color', default='auto', metavar='M',
753 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 758
     # Hack: use OptionGroup text for extra help message after option list
756 759
     option_group = OptionGroup(

+ 88
- 14
tests/test_cdiff.py View File

@@ -108,25 +108,29 @@ class DiffMarkupTest(unittest.TestCase):
108 108
             --- old
109 109
             +++ new
110 110
             hunk header
111
-            @@ -1,4 +1,4 @@
111
+            @@ -1,5 +1,5 @@
112 112
             -hhello
113 113
             +helloo
114 114
             +spammm
115 115
              world
116 116
             -garb
117 117
             -Again
118
+            -	tabbed
118 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 125
         hunk.append(('-', 'hhello\n'))
124 126
         hunk.append(('+', 'helloo\n'))
125 127
         hunk.append(('+', 'spammm\n'))
126 128
         hunk.append((' ', 'world\n'))
127 129
         hunk.append(('-', 'garb\n'))
128 130
         hunk.append(('-', 'Again\n'))
131
+        hunk.append(('-', '	tabbed\n'))
129 132
         hunk.append(('+', 'again\n'))
133
+        hunk.append(('+', ' spaced\n'))
130 134
         diff = cdiff.UnifiedDiff(
131 135
             ['header\n'], '--- old\n', '+++ new\n', [hunk])
132 136
         return diff
@@ -210,8 +214,8 @@ class DiffMarkupTest(unittest.TestCase):
210 214
         diff = self._init_diff()
211 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 220
         sys.stdout.write('\n')
217 221
         for markup in out:
@@ -221,7 +225,7 @@ class DiffMarkupTest(unittest.TestCase):
221 225
         self.assertEqual(out[1], '\x1b[33m--- old\n\x1b[0m')
222 226
         self.assertEqual(out[2], '\x1b[33m+++ new\n\x1b[0m')
223 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 229
         self.assertEqual(
226 230
             out[5],
227 231
             '\x1b[33m1\x1b[0m '
@@ -252,13 +256,19 @@ class DiffMarkupTest(unittest.TestCase):
252 256
             '\x1b[31m\x1b[4m\x1b[31mA\x1b[0m\x1b[31mgain\x1b[0m   '
253 257
             '\x1b[0m\x1b[33m4\x1b[0m '
254 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 266
     # This test is not valid anymore
257 267
     def __test_markup_side_by_side_neg_width(self):
258 268
         diff = self._init_diff()
259 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 273
         self.assertEqual(out[0], '\x1b[36mheader\n\x1b[0m')
264 274
         self.assertEqual(out[1], '\x1b[33m--- old\n\x1b[0m')
@@ -301,8 +311,8 @@ class DiffMarkupTest(unittest.TestCase):
301 311
     def test_markup_side_by_side_off_by_one(self):
302 312
         diff = self._init_diff()
303 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 317
         sys.stdout.write('\n')
308 318
         for markup in out:
@@ -312,7 +322,7 @@ class DiffMarkupTest(unittest.TestCase):
312 322
         self.assertEqual(out[1], '\x1b[33m--- old\n\x1b[0m')
313 323
         self.assertEqual(out[2], '\x1b[33m+++ new\n\x1b[0m')
314 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 326
         self.assertEqual(
317 327
             out[5],
318 328
             '\x1b[33m1\x1b[0m '
@@ -342,12 +352,18 @@ class DiffMarkupTest(unittest.TestCase):
342 352
             '\x1b[31m\x1b[4m\x1b[31mA\x1b[0m\x1b[31mgain\x1b[0m  '
343 353
             '\x1b[0m\x1b[33m4\x1b[0m '
344 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 362
     def test_markup_side_by_side_wrapped(self):
347 363
         diff = self._init_diff()
348 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 368
         sys.stdout.write('\n')
353 369
         for markup in out:
@@ -357,7 +373,7 @@ class DiffMarkupTest(unittest.TestCase):
357 373
         self.assertEqual(out[1], '\x1b[33m--- old\n\x1b[0m')
358 374
         self.assertEqual(out[2], '\x1b[33m+++ new\n\x1b[0m')
359 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 377
         self.assertEqual(
362 378
             out[5],
363 379
             '\x1b[33m1\x1b[0m '
@@ -388,6 +404,64 @@ class DiffMarkupTest(unittest.TestCase):
388 404
             '\x1b[31m\x1b[4m\x1b[31mA\x1b[0m\x1b[31mgain\x1b[0m '
389 405
             '\x1b[0m\x1b[33m4\x1b[0m '
390 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 467
 class UnifiedDiffTest(unittest.TestCase):