Browse Source

Refactor to make logic clearer, no DiffOps anymore

If need to support normal diff, writing a ndiff to udiff translator
makes more sense
Matthew Wang 11 years ago
parent
commit
04ac895387
2 changed files with 251 additions and 296 deletions
  1. 226
    280
      cdiff.py
  2. 25
    16
      tests/test_cdiff.py

+ 226
- 280
cdiff.py View File

@@ -121,49 +121,7 @@ class Hunk(object):
121 121
         return out
122 122
 
123 123
 
124
-class DiffOps(object):      # pragma: no cover
125
-    """Methods in this class are supposed to be overwritten by derived class.
126
-    No is_header() anymore, all non-recognized lines are considered as headers
127
-    """
128
-    def is_old_path(self, line):
129
-        return False
130
-
131
-    def is_new_path(self, line):
132
-        return False
133
-
134
-    def is_hunk_meta(self, line):
135
-        return False
136
-
137
-    def parse_hunk_meta(self, line):
138
-        """Returns a 2-element tuple, each is a tuple of (start, offset)"""
139
-        return None
140
-
141
-    def parse_hunk_line(self, line):
142
-        """Returns a 2-element tuple: (attr, text), where attr is:
143
-                '-': old, '+': new, ' ': common
144
-        """
145
-        return None
146
-
147
-    def is_old(self, line):
148
-        return False
149
-
150
-    def is_new(self, line):
151
-        return False
152
-
153
-    def is_common(self, line):
154
-        return False
155
-
156
-    def is_eof(self, line):
157
-        return False
158
-
159
-    def is_only_in_dir(self, line):
160
-        return False
161
-
162
-    def is_binary_differ(self, line):
163
-        return False
164
-
165
-
166
-class Diff(DiffOps):
124
+class UnifiedDiff(object):
167 125
 
168 126
     def __init__(self, headers, old_path, new_path, hunks):
169 127
         self._headers = headers
@@ -171,206 +129,6 @@ class Diff(DiffOps):
171 129
         self._new_path = new_path
172 130
         self._hunks = hunks
173 131
 
174
-    def markup_traditional(self):
175
-        """Returns a generator"""
176
-        for line in self._headers:
177
-            yield self._markup_header(line)
178
-
179
-        yield self._markup_old_path(self._old_path)
180
-        yield self._markup_new_path(self._new_path)
181
-
182
-        for hunk in self._hunks:
183
-            for hunk_header in hunk._hunk_headers:
184
-                yield self._markup_hunk_header(hunk_header)
185
-            yield self._markup_hunk_meta(hunk._hunk_meta)
186
-            for old, new, changed in hunk.mdiff():
187
-                if changed:
188
-                    if not old[0]:
189
-                        # The '+' char after \x00 is kept
190
-                        # DEBUG: yield 'NEW: %s %s\n' % (old, new)
191
-                        line = new[1].strip('\x00\x01')
192
-                        yield self._markup_new(line)
193
-                    elif not new[0]:
194
-                        # The '-' char after \x00 is kept
195
-                        # DEBUG: yield 'OLD: %s %s\n' % (old, new)
196
-                        line = old[1].strip('\x00\x01')
197
-                        yield self._markup_old(line)
198
-                    else:
199
-                        # DEBUG: yield 'CHG: %s %s\n' % (old, new)
200
-                        yield self._markup_old('-') + \
201
-                            self._markup_mix(old[1], 'red')
202
-                        yield self._markup_new('+') + \
203
-                            self._markup_mix(new[1], 'green')
204
-                else:
205
-                    yield self._markup_common(' ' + old[1])
206
-
207
-    def markup_side_by_side(self, width):
208
-        """Returns a generator"""
209
-        wrap_char = colorize('>', 'lightmagenta')
210
-
211
-        def _normalize(line):
212
-            return line.replace(
213
-                '\t', ' ' * 8).replace('\n', '').replace('\r', '')
214
-
215
-        def _fit_with_marker(text, markup_fn, width, pad=False):
216
-            """Wrap or pad input pure text, then markup"""
217
-            if len(text) > width:
218
-                return markup_fn(text[:(width - 1)]) + wrap_char
219
-            elif pad:
220
-                pad_len = width - len(text)
221
-                return '%s%*s' % (markup_fn(text), pad_len, '')
222
-            else:
223
-                return markup_fn(text)
224
-
225
-        def _fit_with_marker_mix(text, base_color, width, pad=False):
226
-            """Wrap or pad input text which contains mdiff tags, markup at the
227
-            meantime, note only left side need to set `pad`
228
-            """
229
-            out = [COLORS[base_color]]
230
-            count = 0
231
-            tag_re = re.compile(r'\x00[+^-]|\x01')
232
-
233
-            while text and count < width:
234
-                if text.startswith('\x00-'):    # del
235
-                    out.append(COLORS['reverse'] + COLORS[base_color])
236
-                    text = text[2:]
237
-                elif text.startswith('\x00+'):  # add
238
-                    out.append(COLORS['reverse'] + COLORS[base_color])
239
-                    text = text[2:]
240
-                elif text.startswith('\x00^'):  # change
241
-                    out.append(COLORS['underline'] + COLORS[base_color])
242
-                    text = text[2:]
243
-                elif text.startswith('\x01'):   # reset
244
-                    out.append(COLORS['reset'] + COLORS[base_color])
245
-                    text = text[1:]
246
-                else:
247
-                    # FIXME: utf-8 wchar might break the rule here, e.g.
248
-                    # u'\u554a' takes double width of a single letter, also
249
-                    # this depends on your terminal font.  I guess audience of
250
-                    # this tool never put that kind of symbol in their code :-)
251
-                    #
252
-                    out.append(text[0])
253
-                    count += 1
254
-                    text = text[1:]
255
-
256
-            if count == width and tag_re.sub('', text):
257
-                # Was stripped: output fulfil and still has normal char in text
258
-                out[-1] = COLORS['reset'] + wrap_char
259
-            elif count < width and pad:
260
-                pad_len = width - count
261
-                out.append('%s%*s' % (COLORS['reset'], pad_len, ''))
262
-            else:
263
-                out.append(COLORS['reset'])
264
-
265
-            return ''.join(out)
266
-
267
-        # Set up line width
268
-        if width <= 0:
269
-            width = 80
270
-
271
-        # Set up number width, note last hunk might be empty
272
-        try:
273
-            (start, offset) = self._hunks[-1]._old_addr
274
-            max1 = start + offset - 1
275
-            (start, offset) = self._hunks[-1]._new_addr
276
-            max2 = start + offset - 1
277
-        except IndexError:
278
-            max1 = max2 = 0
279
-        num_width = max(len(str(max1)), len(str(max2)))
280
-
281
-        # Setup lineno and line format
282
-        left_num_fmt = colorize('%%(left_num)%ds' % num_width, 'yellow')
283
-        right_num_fmt = colorize('%%(right_num)%ds' % num_width, 'yellow')
284
-        line_fmt = left_num_fmt + ' %(left)s ' + COLORS['reset'] + \
285
-            right_num_fmt + ' %(right)s\n'
286
-
287
-        # yield header, old path and new path
288
-        for line in self._headers:
289
-            yield self._markup_header(line)
290
-        yield self._markup_old_path(self._old_path)
291
-        yield self._markup_new_path(self._new_path)
292
-
293
-        # yield hunks
294
-        for hunk in self._hunks:
295
-            for hunk_header in hunk._hunk_headers:
296
-                yield self._markup_hunk_header(hunk_header)
297
-            yield self._markup_hunk_meta(hunk._hunk_meta)
298
-            for old, new, changed in hunk.mdiff():
299
-                if old[0]:
300
-                    left_num = str(hunk._old_addr[0] + int(old[0]) - 1)
301
-                else:
302
-                    left_num = ' '
303
-
304
-                if new[0]:
305
-                    right_num = str(hunk._new_addr[0] + int(new[0]) - 1)
306
-                else:
307
-                    right_num = ' '
308
-
309
-                left = _normalize(old[1])
310
-                right = _normalize(new[1])
311
-
312
-                if changed:
313
-                    if not old[0]:
314
-                        left = '%*s' % (width, ' ')
315
-                        right = right.lstrip('\x00+').rstrip('\x01')
316
-                        right = _fit_with_marker(
317
-                            right, self._markup_new, width)
318
-                    elif not new[0]:
319
-                        left = left.lstrip('\x00-').rstrip('\x01')
320
-                        left = _fit_with_marker(left, self._markup_old, width)
321
-                        right = ''
322
-                    else:
323
-                        left = _fit_with_marker_mix(left, 'red', width, 1)
324
-                        right = _fit_with_marker_mix(right, 'green', width)
325
-                else:
326
-                    left = _fit_with_marker(
327
-                        left, self._markup_common, width, 1)
328
-                    right = _fit_with_marker(right, self._markup_common, width)
329
-                yield line_fmt % {
330
-                    'left_num': left_num,
331
-                    'left': left,
332
-                    'right_num': right_num,
333
-                    'right': right
334
-                }
335
-
336
-    def _markup_header(self, line):
337
-        return colorize(line, 'cyan')
338
-
339
-    def _markup_old_path(self, line):
340
-        return colorize(line, 'yellow')
341
-
342
-    def _markup_new_path(self, line):
343
-        return colorize(line, 'yellow')
344
-
345
-    def _markup_hunk_header(self, line):
346
-        return colorize(line, 'lightcyan')
347
-
348
-    def _markup_hunk_meta(self, line):
349
-        return colorize(line, 'lightblue')
350
-
351
-    def _markup_common(self, line):
352
-        return colorize(line, 'reset')
353
-
354
-    def _markup_old(self, line):
355
-        return colorize(line, 'lightred')
356
-
357
-    def _markup_new(self, line):
358
-        return colorize(line, 'lightgreen')
359
-
360
-    def _markup_mix(self, line, base_color):
361
-        del_code = COLORS['reverse'] + COLORS[base_color]
362
-        add_code = COLORS['reverse'] + COLORS[base_color]
363
-        chg_code = COLORS['underline'] + COLORS[base_color]
364
-        rst_code = COLORS['reset'] + COLORS[base_color]
365
-        line = line.replace('\x00-', del_code)
366
-        line = line.replace('\x00+', add_code)
367
-        line = line.replace('\x00^', chg_code)
368
-        line = line.replace('\x01', rst_code)
369
-        return colorize(line, base_color)
370
-
371
-
372
-class UnifiedDiff(Diff):
373
-
374 132
     def is_old_path(self, line):
375 133
         return line.startswith('--- ')
376 134
 
@@ -551,46 +309,45 @@ class DiffParser(object):
551 309
             self._stream = stream
552 310
 
553 311
     def get_diff_generator(self):
554
-        """parse all diff lines, construct a list of Diff objects"""
555
-        difflet = UnifiedDiff(None, None, None, None)
556
-        diff = Diff([], None, None, [])
312
+        """parse all diff lines, construct a list of UnifiedDiff objects"""
313
+        diff = UnifiedDiff([], None, None, [])
557 314
         headers = []
558 315
 
559 316
         for line in self._stream:
560 317
             line = decode(line)
561 318
 
562
-            if difflet.is_old_path(line):
319
+            if diff.is_old_path(line):
563 320
                 # FIXME: '--- ' breaks here, better to probe next line
564 321
                 if diff._old_path and diff._new_path and diff._hunks:
565 322
                     # See a new diff, yield previous diff if exists
566 323
                     yield diff
567
-                diff = Diff(headers, line, None, [])
324
+                diff = UnifiedDiff(headers, line, None, [])
568 325
                 headers = []
569 326
 
570
-            elif difflet.is_new_path(line) and diff._old_path:
327
+            elif diff.is_new_path(line) and diff._old_path:
571 328
                 diff._new_path = line
572 329
 
573
-            elif difflet.is_hunk_meta(line):
330
+            elif diff.is_hunk_meta(line):
574 331
                 hunk_meta = line
575 332
                 try:
576
-                    old_addr, new_addr = difflet.parse_hunk_meta(hunk_meta)
333
+                    old_addr, new_addr = diff.parse_hunk_meta(hunk_meta)
577 334
                 except (IndexError, ValueError):
578 335
                     raise RuntimeError('invalid hunk meta: %s' % hunk_meta)
579 336
                 hunk = Hunk(headers, hunk_meta, old_addr, new_addr)
580 337
                 headers = []
581 338
                 diff._hunks.append(hunk)
582 339
 
583
-            elif diff._hunks and not headers and (difflet.is_old(line) or
584
-                                                  difflet.is_new(line) or
585
-                                                  difflet.is_common(line)):
586
-                diff._hunks[-1].append(difflet.parse_hunk_line(line))
340
+            elif diff._hunks and not headers and (diff.is_old(line) or
341
+                                                  diff.is_new(line) or
342
+                                                  diff.is_common(line)):
343
+                diff._hunks[-1].append(diff.parse_hunk_line(line))
587 344
 
588
-            elif difflet.is_eof(line):
345
+            elif diff.is_eof(line):
589 346
                 # ignore
590 347
                 pass
591 348
 
592
-            elif difflet.is_only_in_dir(line) or \
593
-                    difflet.is_binary_differ(line):
349
+            elif diff.is_only_in_dir(line) or \
350
+                    diff.is_binary_differ(line):
594 351
                 # 'Only in foo:' and 'Binary files ... differ' are considered
595 352
                 # as separate diffs, so yield current diff, then this line
596 353
                 #
@@ -598,9 +355,9 @@ class DiffParser(object):
598 355
                     # Current diff is comppletely constructed
599 356
                     yield diff
600 357
                 headers.append(line)
601
-                yield Diff(headers, '', '', [])
358
+                yield UnifiedDiff(headers, '', '', [])
602 359
                 headers = []
603
-                diff = Diff([], None, None, [])
360
+                diff = UnifiedDiff([], None, None, [])
604 361
 
605 362
             else:
606 363
                 # All other non-recognized lines are considered as headers or
@@ -617,38 +374,227 @@ class DiffParser(object):
617 374
             yield diff
618 375
 
619 376
         if headers:
620
-            # Tolerate dangling headers, just yield a Diff object with only
621
-            # header lines
377
+            # Tolerate dangling headers, just yield a UnifiedDiff object with
378
+            # only header lines
622 379
             #
623
-            yield Diff(headers, '', '', [])
380
+            yield UnifiedDiff(headers, '', '', [])
624 381
 
625 382
 
626
-class DiffMarkup(object):
383
+class DiffMarker(object):
627 384
 
628
-    def __init__(self, stream):
629
-        self._diffs = DiffParser(stream).get_diff_generator()
630
-
631
-    def markup(self, side_by_side=False, width=0):
385
+    def markup(self, diffs, side_by_side=False, width=0):
632 386
         """Returns a generator"""
633 387
         if side_by_side:
634
-            return self._markup_side_by_side(width)
388
+            for diff in diffs:
389
+                for line in self._markup_side_by_side(diff, width):
390
+                    yield line
635 391
         else:
636
-            return self._markup_traditional()
392
+            for diff in diffs:
393
+                for line in self._markup_traditional(diff):
394
+                    yield line
637 395
 
638
-    def _markup_traditional(self):
639
-        for diff in self._diffs:
640
-            for line in diff.markup_traditional():
641
-                yield line
396
+    def _markup_traditional(self, diff):
397
+        """Returns a generator"""
398
+        for line in diff._headers:
399
+            yield self._markup_header(line)
642 400
 
643
-    def _markup_side_by_side(self, width):
644
-        for diff in self._diffs:
645
-            for line in diff.markup_side_by_side(width):
646
-                yield line
401
+        yield self._markup_old_path(diff._old_path)
402
+        yield self._markup_new_path(diff._new_path)
403
+
404
+        for hunk in diff._hunks:
405
+            for hunk_header in hunk._hunk_headers:
406
+                yield self._markup_hunk_header(hunk_header)
407
+            yield self._markup_hunk_meta(hunk._hunk_meta)
408
+            for old, new, changed in hunk.mdiff():
409
+                if changed:
410
+                    if not old[0]:
411
+                        # The '+' char after \x00 is kept
412
+                        # DEBUG: yield 'NEW: %s %s\n' % (old, new)
413
+                        line = new[1].strip('\x00\x01')
414
+                        yield self._markup_new(line)
415
+                    elif not new[0]:
416
+                        # The '-' char after \x00 is kept
417
+                        # DEBUG: yield 'OLD: %s %s\n' % (old, new)
418
+                        line = old[1].strip('\x00\x01')
419
+                        yield self._markup_old(line)
420
+                    else:
421
+                        # DEBUG: yield 'CHG: %s %s\n' % (old, new)
422
+                        yield self._markup_old('-') + \
423
+                            self._markup_mix(old[1], 'red')
424
+                        yield self._markup_new('+') + \
425
+                            self._markup_mix(new[1], 'green')
426
+                else:
427
+                    yield self._markup_common(' ' + old[1])
428
+
429
+    def _markup_side_by_side(self, diff, width):
430
+        """Returns a generator"""
431
+        wrap_char = colorize('>', 'lightmagenta')
432
+
433
+        def _normalize(line):
434
+            return line.replace(
435
+                '\t', ' ' * 8).replace('\n', '').replace('\r', '')
436
+
437
+        def _fit_with_marker(text, markup_fn, width, pad=False):
438
+            """Wrap or pad input pure text, then markup"""
439
+            if len(text) > width:
440
+                return markup_fn(text[:(width - 1)]) + wrap_char
441
+            elif pad:
442
+                pad_len = width - len(text)
443
+                return '%s%*s' % (markup_fn(text), pad_len, '')
444
+            else:
445
+                return markup_fn(text)
446
+
447
+        def _fit_with_marker_mix(text, base_color, width, pad=False):
448
+            """Wrap or pad input text which contains mdiff tags, markup at the
449
+            meantime, note only left side need to set `pad`
450
+            """
451
+            out = [COLORS[base_color]]
452
+            count = 0
453
+            tag_re = re.compile(r'\x00[+^-]|\x01')
454
+
455
+            while text and count < width:
456
+                if text.startswith('\x00-'):    # del
457
+                    out.append(COLORS['reverse'] + COLORS[base_color])
458
+                    text = text[2:]
459
+                elif text.startswith('\x00+'):  # add
460
+                    out.append(COLORS['reverse'] + COLORS[base_color])
461
+                    text = text[2:]
462
+                elif text.startswith('\x00^'):  # change
463
+                    out.append(COLORS['underline'] + COLORS[base_color])
464
+                    text = text[2:]
465
+                elif text.startswith('\x01'):   # reset
466
+                    out.append(COLORS['reset'] + COLORS[base_color])
467
+                    text = text[1:]
468
+                else:
469
+                    # FIXME: utf-8 wchar might break the rule here, e.g.
470
+                    # u'\u554a' takes double width of a single letter, also
471
+                    # this depends on your terminal font.  I guess audience of
472
+                    # this tool never put that kind of symbol in their code :-)
473
+                    #
474
+                    out.append(text[0])
475
+                    count += 1
476
+                    text = text[1:]
477
+
478
+            if count == width and tag_re.sub('', text):
479
+                # Was stripped: output fulfil and still has normal char in text
480
+                out[-1] = COLORS['reset'] + wrap_char
481
+            elif count < width and pad:
482
+                pad_len = width - count
483
+                out.append('%s%*s' % (COLORS['reset'], pad_len, ''))
484
+            else:
485
+                out.append(COLORS['reset'])
486
+
487
+            return ''.join(out)
488
+
489
+        # Set up line width
490
+        if width <= 0:
491
+            width = 80
492
+
493
+        # Set up number width, note last hunk might be empty
494
+        try:
495
+            (start, offset) = diff._hunks[-1]._old_addr
496
+            max1 = start + offset - 1
497
+            (start, offset) = diff._hunks[-1]._new_addr
498
+            max2 = start + offset - 1
499
+        except IndexError:
500
+            max1 = max2 = 0
501
+        num_width = max(len(str(max1)), len(str(max2)))
502
+
503
+        # Setup lineno and line format
504
+        left_num_fmt = colorize('%%(left_num)%ds' % num_width, 'yellow')
505
+        right_num_fmt = colorize('%%(right_num)%ds' % num_width, 'yellow')
506
+        line_fmt = left_num_fmt + ' %(left)s ' + COLORS['reset'] + \
507
+            right_num_fmt + ' %(right)s\n'
508
+
509
+        # yield header, old path and new path
510
+        for line in diff._headers:
511
+            yield self._markup_header(line)
512
+        yield self._markup_old_path(diff._old_path)
513
+        yield self._markup_new_path(diff._new_path)
514
+
515
+        # yield hunks
516
+        for hunk in diff._hunks:
517
+            for hunk_header in hunk._hunk_headers:
518
+                yield self._markup_hunk_header(hunk_header)
519
+            yield self._markup_hunk_meta(hunk._hunk_meta)
520
+            for old, new, changed in hunk.mdiff():
521
+                if old[0]:
522
+                    left_num = str(hunk._old_addr[0] + int(old[0]) - 1)
523
+                else:
524
+                    left_num = ' '
525
+
526
+                if new[0]:
527
+                    right_num = str(hunk._new_addr[0] + int(new[0]) - 1)
528
+                else:
529
+                    right_num = ' '
530
+
531
+                left = _normalize(old[1])
532
+                right = _normalize(new[1])
533
+
534
+                if changed:
535
+                    if not old[0]:
536
+                        left = '%*s' % (width, ' ')
537
+                        right = right.lstrip('\x00+').rstrip('\x01')
538
+                        right = _fit_with_marker(
539
+                            right, self._markup_new, width)
540
+                    elif not new[0]:
541
+                        left = left.lstrip('\x00-').rstrip('\x01')
542
+                        left = _fit_with_marker(left, self._markup_old, width)
543
+                        right = ''
544
+                    else:
545
+                        left = _fit_with_marker_mix(left, 'red', width, 1)
546
+                        right = _fit_with_marker_mix(right, 'green', width)
547
+                else:
548
+                    left = _fit_with_marker(
549
+                        left, self._markup_common, width, 1)
550
+                    right = _fit_with_marker(right, self._markup_common, width)
551
+                yield line_fmt % {
552
+                    'left_num': left_num,
553
+                    'left': left,
554
+                    'right_num': right_num,
555
+                    'right': right
556
+                }
557
+
558
+    def _markup_header(self, line):
559
+        return colorize(line, 'cyan')
560
+
561
+    def _markup_old_path(self, line):
562
+        return colorize(line, 'yellow')
563
+
564
+    def _markup_new_path(self, line):
565
+        return colorize(line, 'yellow')
566
+
567
+    def _markup_hunk_header(self, line):
568
+        return colorize(line, 'lightcyan')
569
+
570
+    def _markup_hunk_meta(self, line):
571
+        return colorize(line, 'lightblue')
572
+
573
+    def _markup_common(self, line):
574
+        return colorize(line, 'reset')
575
+
576
+    def _markup_old(self, line):
577
+        return colorize(line, 'lightred')
578
+
579
+    def _markup_new(self, line):
580
+        return colorize(line, 'lightgreen')
581
+
582
+    def _markup_mix(self, line, base_color):
583
+        del_code = COLORS['reverse'] + COLORS[base_color]
584
+        add_code = COLORS['reverse'] + COLORS[base_color]
585
+        chg_code = COLORS['underline'] + COLORS[base_color]
586
+        rst_code = COLORS['reset'] + COLORS[base_color]
587
+        line = line.replace('\x00-', del_code)
588
+        line = line.replace('\x00+', add_code)
589
+        line = line.replace('\x00^', chg_code)
590
+        line = line.replace('\x01', rst_code)
591
+        return colorize(line, base_color)
647 592
 
648 593
 
649 594
 def markup_to_pager(stream, opts):
650
-    markup = DiffMarkup(stream)
651
-    color_diff = markup.markup(side_by_side=opts.side_by_side,
595
+    diffs = DiffParser(stream).get_diff_generator()
596
+    marker = DiffMarker()
597
+    color_diff = marker.markup(diffs, side_by_side=opts.side_by_side,
652 598
                                width=opts.width)
653 599
 
654 600
     # Args stolen from git source: github.com/git/git/blob/master/pager.c

+ 25
- 16
tests/test_cdiff.py View File

@@ -88,7 +88,7 @@ class HunkTest(unittest.TestCase):
88 88
         self.assertEqual(hunk._get_new_text(), ['bar\n', 'common\n'])
89 89
 
90 90
 
91
-class DiffTest(unittest.TestCase):
91
+class DiffMarkupTest(unittest.TestCase):
92 92
 
93 93
     def _init_diff(self):
94 94
         """Return a minimal diff contains all required samples
@@ -115,24 +115,25 @@ class DiffTest(unittest.TestCase):
115 115
         hunk.append(('-', 'garb\n'))
116 116
         hunk.append(('-', 'Again\n'))
117 117
         hunk.append(('+', 'again\n'))
118
-        diff = cdiff.Diff(['header\n'], '--- old\n', '+++ new\n', [hunk])
118
+        diff = cdiff.UnifiedDiff(['header\n'], '--- old\n', '+++ new\n', [hunk])
119 119
         return diff
120 120
 
121 121
     def test_markup_mix(self):
122
+        marker = cdiff.DiffMarker()
122 123
         line = 'foo \x00-del\x01 \x00+add\x01 \x00^chg\x01 bar'
123 124
         base_color = 'red'
124
-        diff = cdiff.Diff(None, None, None, None)
125 125
         self.assertEqual(
126
-            diff._markup_mix(line, base_color),
126
+            marker._markup_mix(line, base_color),
127 127
             '\x1b[31mfoo \x1b[7m\x1b[31mdel\x1b[0m\x1b[31m '
128 128
             '\x1b[7m\x1b[31madd\x1b[0m\x1b[31m '
129 129
             '\x1b[4m\x1b[31mchg\x1b[0m\x1b[31m bar\x1b[0m')
130 130
 
131 131
     def test_markup_traditional_hunk_header(self):
132 132
         hunk = cdiff.Hunk(['hunk header\n'], '@@ -0 +0 @@\n', (0, 0), (0, 0))
133
-        diff = cdiff.Diff([], '--- old\n', '+++ new\n', [hunk])
133
+        diff = cdiff.UnifiedDiff([], '--- old\n', '+++ new\n', [hunk])
134
+        marker = cdiff.DiffMarker()
134 135
 
135
-        out = list(diff.markup_traditional())
136
+        out = list(marker._markup_traditional(diff))
136 137
         self.assertEqual(len(out), 4)
137 138
 
138 139
         self.assertEqual(out[0], '\x1b[33m--- old\n\x1b[0m')
@@ -143,9 +144,10 @@ class DiffTest(unittest.TestCase):
143 144
     def test_markup_traditional_old_changed(self):
144 145
         hunk = cdiff.Hunk([], '@@ -1 +0,0 @@\n', (1, 0), (0, 0))
145 146
         hunk.append(('-', 'spam\n'))
146
-        diff = cdiff.Diff([], '--- old\n', '+++ new\n', [hunk])
147
+        diff = cdiff.UnifiedDiff([], '--- old\n', '+++ new\n', [hunk])
148
+        marker = cdiff.DiffMarker()
147 149
 
148
-        out = list(diff.markup_traditional())
150
+        out = list(marker._markup_traditional(diff))
149 151
         self.assertEqual(len(out), 4)
150 152
 
151 153
         self.assertEqual(out[0], '\x1b[33m--- old\n\x1b[0m')
@@ -156,9 +158,10 @@ class DiffTest(unittest.TestCase):
156 158
     def test_markup_traditional_new_changed(self):
157 159
         hunk = cdiff.Hunk([], '@@ -0,0 +1 @@\n', (0, 0), (1, 0))
158 160
         hunk.append(('+', 'spam\n'))
159
-        diff = cdiff.Diff([], '--- old\n', '+++ new\n', [hunk])
161
+        diff = cdiff.UnifiedDiff([], '--- old\n', '+++ new\n', [hunk])
162
+        marker = cdiff.DiffMarker()
160 163
 
161
-        out = list(diff.markup_traditional())
164
+        out = list(marker._markup_traditional(diff))
162 165
         self.assertEqual(len(out), 4)
163 166
 
164 167
         self.assertEqual(out[0], '\x1b[33m--- old\n\x1b[0m')
@@ -171,9 +174,10 @@ class DiffTest(unittest.TestCase):
171 174
         hunk.append(('-', 'hella\n'))
172 175
         hunk.append(('+', 'hello\n'))
173 176
         hunk.append((' ', 'common\n'))
174
-        diff = cdiff.Diff([], '--- old\n', '+++ new\n', [hunk])
177
+        diff = cdiff.UnifiedDiff([], '--- old\n', '+++ new\n', [hunk])
178
+        marker = cdiff.DiffMarker()
175 179
 
176
-        out = list(diff.markup_traditional())
180
+        out = list(marker._markup_traditional(diff))
177 181
         self.assertEqual(len(out), 6)
178 182
 
179 183
         self.assertEqual(out[0], '\x1b[33m--- old\n\x1b[0m')
@@ -191,7 +195,9 @@ class DiffTest(unittest.TestCase):
191 195
 
192 196
     def test_markup_side_by_side_padded(self):
193 197
         diff = self._init_diff()
194
-        out = list(diff.markup_side_by_side(7))
198
+        marker = cdiff.DiffMarker()
199
+
200
+        out = list(marker._markup_side_by_side(diff, 7))
195 201
         self.assertEqual(len(out), 10)
196 202
 
197 203
         sys.stdout.write('\n')
@@ -236,7 +242,8 @@ class DiffTest(unittest.TestCase):
236 242
 
237 243
     def test_markup_side_by_side_neg_width(self):
238 244
         diff = self._init_diff()
239
-        out = list(diff.markup_side_by_side(-1))
245
+        marker = cdiff.DiffMarker()
246
+        out = list(marker._markup_side_by_side(diff, -1))
240 247
         self.assertEqual(len(out), 10)
241 248
 
242 249
         self.assertEqual(out[0], '\x1b[36mheader\n\x1b[0m')
@@ -279,7 +286,8 @@ class DiffTest(unittest.TestCase):
279 286
 
280 287
     def test_markup_side_by_side_off_by_one(self):
281 288
         diff = self._init_diff()
282
-        out = list(diff.markup_side_by_side(6))
289
+        marker = cdiff.DiffMarker()
290
+        out = list(marker._markup_side_by_side(diff, 6))
283 291
         self.assertEqual(len(out), 10)
284 292
 
285 293
         sys.stdout.write('\n')
@@ -323,7 +331,8 @@ class DiffTest(unittest.TestCase):
323 331
 
324 332
     def test_markup_side_by_side_wrapped(self):
325 333
         diff = self._init_diff()
326
-        out = list(diff.markup_side_by_side(5))
334
+        marker = cdiff.DiffMarker()
335
+        out = list(marker._markup_side_by_side(diff, 5))
327 336
         self.assertEqual(len(out), 10)
328 337
 
329 338
         sys.stdout.write('\n')