typocheck 0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: be4f13ece69030625fe9d5dce56681ec9a1da969
4
+ data.tar.gz: 8656abeff7944ff60386eb00069c2d3c22016590
5
+ SHA512:
6
+ metadata.gz: b161ad2fc066b00c6f71e22b095ec5a619bf51692493608ff918404f127b5dc8f59a147003582fdc9a4a101cc6159929562c235e7c45c6a9cacbd938f7fa83dc
7
+ data.tar.gz: 2d5a15f486f61c7e0b1a16eb482f89aac0ed255851880fa48039ffd296e78e1bbbfccbe45d937f65ceb1baaacf3eaa83e71386cfae11f987f52dd8f385dcb9e0
@@ -0,0 +1,37 @@
1
+ ### typocheck
2
+
3
+ comments typo checking tool
4
+
5
+ ==========
6
+
7
+ ### Usage
8
+
9
+ ```
10
+ Check typo for a source code
11
+ $ bin/typocheck -f helloword.rb
12
+ Get more help with
13
+ $ bin/typocheck -h
14
+ ```
15
+
16
+ ### License
17
+
18
+ typocheck is published under MIT License
19
+
20
+ Copyright (c) 2014 Minghe Huang (@metrue)
21
+
22
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
23
+ this software and associated documentation files (the "Software"), to deal in
24
+ the Software without restriction, including without limitation the rights to use,
25
+ copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
26
+ Software, and to permit persons to whom the Software is furnished to do so,
27
+ subject to the following conditions:
28
+
29
+ The above copyright notice and this permission notice shall be included in all
30
+ copies or substantial portions of the Software.
31
+
32
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
34
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
35
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
36
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
37
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,610 @@
1
+ #!/usr/bin/env python
2
+
3
+ """ icdiff.py
4
+
5
+ Author: Jeff Kaufman, derived from difflib.HtmlDiff
6
+
7
+ License: This code is usable under the same open terms as the rest of
8
+ python. See: http://www.python.org/psf/license/
9
+
10
+ """
11
+
12
+ import os
13
+ import sys
14
+ import errno
15
+ import difflib
16
+ from optparse import Option, OptionParser
17
+ import re
18
+ import filecmp
19
+ import unicodedata
20
+ import codecs
21
+
22
+ __version__ = "1.7.2"
23
+
24
+ color_codes = {
25
+ "red": '\033[0;31m',
26
+ "green": '\033[0;32m',
27
+ "yellow": '\033[0;33m',
28
+ "blue": '\033[0;34m',
29
+ "magenta": '\033[0;35m',
30
+ "cyan": '\033[0;36m',
31
+ "none": '\033[m',
32
+ "red_bold": '\033[1;31m',
33
+ "green_bold": '\033[1;32m',
34
+ "yellow_bold": '\033[1;33m',
35
+ "blue_bold": '\033[1;34m',
36
+ "magenta_bold": '\033[1;35m',
37
+ "cyan_bold": '\033[1;36m',
38
+ }
39
+
40
+ class ConsoleDiff(object):
41
+ """Console colored side by side comparison with change highlights.
42
+
43
+ Based on difflib.HtmlDiff
44
+
45
+ This class can be used to create a text-mode table showing a side
46
+
47
+ by side, line by line comparison of text with inter-line and
48
+ intra-line change highlights in ansi color escape sequences as
49
+ intra-line change highlights in ansi color escape sequences as
50
+ read by xterm. The table can be generated in either full or
51
+ contextual difference mode.
52
+
53
+ To generate the table, call make_table.
54
+
55
+ Usage is the almost the same as HtmlDiff except only make_table is
56
+ implemented and the file can be invoked on the command line.
57
+ Run::
58
+
59
+ python icdiff.py --help
60
+
61
+ for command line usage information.
62
+
63
+ """
64
+
65
+ def __init__(self, tabsize=8, wrapcolumn=None, linejunk=None,
66
+ charjunk=difflib.IS_CHARACTER_JUNK, cols=80,
67
+ line_numbers=False,
68
+ show_all_spaces=False,
69
+ highlight=False,
70
+ no_bold=False):
71
+ """ConsoleDiff instance initializer
72
+
73
+ Arguments:
74
+ tabsize -- tab stop spacing, defaults to 8.
75
+ wrapcolumn -- column number where lines are broken and wrapped,
76
+ defaults to None where lines are not wrapped.
77
+ linejunk, charjunk -- keyword arguments passed into ndiff() (used by
78
+ ConsoleDiff() to generate the side by side differences). See
79
+ ndiff() documentation for argument default values and descriptions.
80
+ """
81
+
82
+ self._tabsize = tabsize
83
+ self.line_numbers = line_numbers
84
+ self.cols = cols
85
+ self.show_all_spaces = show_all_spaces
86
+ self.highlight = highlight
87
+ self.no_bold = no_bold
88
+
89
+ if wrapcolumn is None:
90
+ if not line_numbers:
91
+ wrapcolumn = self.cols // 2 - 2
92
+ else:
93
+ wrapcolumn = self.cols // 2 - 10
94
+
95
+ self._wrapcolumn = wrapcolumn
96
+ self._linejunk = linejunk
97
+ self._charjunk = charjunk
98
+
99
+ def _tab_newline_replace(self, fromlines, tolines):
100
+ """Returns from/to line lists with tabs expanded and newlines removed.
101
+
102
+ Instead of tab characters being replaced by the number of spaces
103
+ needed to fill in to the next tab stop, this function will fill
104
+ the space with tab characters. This is done so that the difference
105
+ algorithms can identify changes in a file when tabs are replaced by
106
+ spaces and vice versa. At the end of the table generation, the tab
107
+ characters will be replaced with a space.
108
+ """
109
+ def expand_tabs(line):
110
+ # hide real spaces
111
+ line = line.replace(' ', '\0')
112
+ # expand tabs into spaces
113
+ line = line.expandtabs(self._tabsize)
114
+ # relace spaces from expanded tabs back into tab characters
115
+ # (we'll replace them with markup after we do differencing)
116
+ line = line.replace(' ', '\t')
117
+ return line.replace('\0', ' ').rstrip('\n')
118
+ fromlines = [expand_tabs(line) for line in fromlines]
119
+ tolines = [expand_tabs(line) for line in tolines]
120
+ return fromlines, tolines
121
+
122
+ def _display_len(self, s):
123
+ # Handle wide characters like chinese.
124
+ def width(c):
125
+ if ((isinstance(c, type(u"")) and
126
+ unicodedata.east_asian_width(c) == 'W')):
127
+ return 2
128
+ return 1
129
+
130
+ return sum(width(c) for c in s)
131
+
132
+ def _split_line(self, data_list, line_num, text):
133
+ """Builds list of text lines by splitting text lines at wrap point
134
+
135
+ This function will determine if the input text line needs to be
136
+ wrapped (split) into separate lines. If so, the first wrap point
137
+ will be determined and the first line appended to the output
138
+ text line list. This function is used recursively to handle
139
+ the second part of the split line to further split it.
140
+ """
141
+ # if blank line or context separator, just add it to the output list
142
+ if not line_num:
143
+ data_list.append((line_num, text))
144
+ return
145
+
146
+ # if line text doesn't need wrapping, just add it to the output list
147
+ if ((self._display_len(text) - (text.count('\0') * 3) <=
148
+ self._wrapcolumn)):
149
+ data_list.append((line_num, text))
150
+ return
151
+
152
+ # scan text looking for the wrap point, keeping track if the wrap
153
+ # point is inside markers
154
+ i = 0
155
+ n = 0
156
+ mark = ''
157
+ while n < self._wrapcolumn and i < len(text):
158
+ if text[i] == '\0':
159
+ i += 1
160
+ mark = text[i]
161
+ i += 1
162
+ elif text[i] == '\1':
163
+ i += 1
164
+ mark = ''
165
+ else:
166
+ n += self._display_len(text[i])
167
+ i += 1
168
+
169
+ # wrap point is inside text, break it up into separate lines
170
+ line1 = text[:i]
171
+ line2 = text[i:]
172
+
173
+ # if wrap point is inside markers, place end marker at end of first
174
+ # line and start marker at beginning of second line because each
175
+ # line will have its own table tag markup around it.
176
+ if mark:
177
+ line1 = line1 + '\1'
178
+ line2 = '\0' + mark + line2
179
+
180
+ # tack on first line onto the output list
181
+ data_list.append((line_num, line1))
182
+
183
+ # use this routine again to wrap the remaining text
184
+ self._split_line(data_list, '>', line2)
185
+
186
+ def _line_wrapper(self, diffs):
187
+ """Returns iterator that splits (wraps) mdiff text lines"""
188
+
189
+ # pull from/to data and flags from mdiff iterator
190
+ for fromdata, todata, flag in diffs:
191
+ # check for context separators and pass them through
192
+ if flag is None:
193
+ yield fromdata, todata, flag
194
+ continue
195
+ (fromline, fromtext), (toline, totext) = fromdata, todata
196
+ # for each from/to line split it at the wrap column to form
197
+ # list of text lines.
198
+ fromlist, tolist = [], []
199
+ self._split_line(fromlist, fromline, fromtext)
200
+ self._split_line(tolist, toline, totext)
201
+ # yield from/to line in pairs inserting blank lines as
202
+ # necessary when one side has more wrapped lines
203
+ while fromlist or tolist:
204
+ if fromlist:
205
+ fromdata = fromlist.pop(0)
206
+ else:
207
+ fromdata = ('', ' ')
208
+ if tolist:
209
+ todata = tolist.pop(0)
210
+ else:
211
+ todata = ('', ' ')
212
+ yield fromdata, todata, flag
213
+
214
+ def _collect_lines(self, diffs):
215
+ """Collects mdiff output into separate lists
216
+
217
+ Before storing the mdiff from/to data into a list, it is converted
218
+ into a single line of text with console markup.
219
+ """
220
+
221
+ fromlist, tolist, flaglist = [], [], []
222
+ # pull from/to data and flags from mdiff style iterator
223
+ for fromdata, todata, flag in diffs:
224
+ if (fromdata, todata, flag) == (None, None, None):
225
+ yield None
226
+ else:
227
+ yield (self._format_line(*fromdata),
228
+ self._format_line(*todata))
229
+
230
+ def _format_line(self, linenum, text):
231
+ text = text.rstrip()
232
+ if not self.line_numbers:
233
+ return text
234
+ return self._add_line_numbers(linenum, text)
235
+
236
+ def _add_line_numbers(self, linenum, text):
237
+ try:
238
+ lid = '%d' % linenum
239
+ except TypeError:
240
+ # handle blank lines where linenum is '>' or ''
241
+ lid = ''
242
+ return text
243
+ return '%s %s' % (self._rpad(lid, 8), text)
244
+
245
+ def _real_len(self, s):
246
+ l = 0
247
+ in_esc = False
248
+ prev = ' '
249
+ for c in replace_all({'\0+': "",
250
+ '\0-': "",
251
+ '\0^': "",
252
+ '\1': "",
253
+ '\t': ' '}, s):
254
+ if in_esc:
255
+ if c == "m":
256
+ in_esc = False
257
+ else:
258
+ if c == "[" and prev == "\033":
259
+ in_esc = True
260
+ l -= 1 # we counted prev when we shouldn't have
261
+ else:
262
+ l += self._display_len(c)
263
+ prev = c
264
+
265
+ return l
266
+
267
+ def _rpad(self, s, field_width):
268
+ return self._pad(s, field_width) + s
269
+
270
+ def _pad(self, s, field_width):
271
+ return " " * (field_width - self._real_len(s))
272
+
273
+ def _lpad(self, s, field_width):
274
+ return s + self._pad(s, field_width)
275
+
276
+ def make_table(self, fromlines, tolines, fromdesc='', todesc='',
277
+ context=False, numlines=5):
278
+ """Generates table of side by side comparison with change highlights
279
+
280
+ Arguments:
281
+ fromlines -- list of "from" lines
282
+ tolines -- list of "to" lines
283
+ fromdesc -- "from" file column header string
284
+ todesc -- "to" file column header string
285
+ context -- set to True for contextual differences (defaults to False
286
+ which shows full differences).
287
+ numlines -- number of context lines. When context is set True,
288
+ controls number of lines displayed before and after the change.
289
+ When context is False, controls the number of lines to place
290
+ the "next" link anchors before the next change (so click of
291
+ "next" link jumps to just before the change).
292
+ """
293
+ if context:
294
+ context_lines = numlines
295
+ else:
296
+ context_lines = None
297
+
298
+ # change tabs to spaces before it gets more difficult after we insert
299
+ # markup
300
+ fromlines, tolines = self._tab_newline_replace(fromlines, tolines)
301
+
302
+ # create diffs iterator which generates side by side from/to data
303
+ diffs = difflib._mdiff(fromlines, tolines, context_lines,
304
+ linejunk=self._linejunk,
305
+ charjunk=self._charjunk)
306
+
307
+ # set up iterator to wrap lines that exceed desired width
308
+ if self._wrapcolumn:
309
+ diffs = self._line_wrapper(diffs)
310
+ diffs = self._collect_lines(diffs)
311
+
312
+ for left, right in self._generate_table(fromdesc, todesc, diffs):
313
+ yield self.colorize(
314
+ "%s %s" % (self._lpad(left, self.cols // 2 - 1),
315
+ self._lpad(right, self.cols // 2 - 1)))
316
+
317
+ def _generate_table(self, fromdesc, todesc, diffs):
318
+ if fromdesc or todesc:
319
+ yield (simple_colorize(fromdesc, "blue"),
320
+ simple_colorize(todesc, "blue"))
321
+
322
+ for i, line in enumerate(diffs):
323
+ if line is None:
324
+ # mdiff yields None on separator lines; skip the bogus ones
325
+ # generated for the first line
326
+ if i > 0:
327
+ yield (simple_colorize('---', "blue"),
328
+ simple_colorize('---', "blue"))
329
+ else:
330
+ yield line
331
+
332
+ def colorize(self, s):
333
+ def background(color):
334
+ return replace_all({"\033[1;": "\033[7;",
335
+ "\033[0;": "\033[7;"}, color)
336
+
337
+ if self.no_bold:
338
+ C_ADD = color_codes["green"]
339
+ C_SUB = color_codes["red"]
340
+ C_CHG = color_codes["yellow"]
341
+ else:
342
+ C_ADD = color_codes["green_bold"]
343
+ C_SUB = color_codes["red_bold"]
344
+ C_CHG = color_codes["yellow_bold"]
345
+
346
+ if self.highlight:
347
+ C_ADD, C_SUB, C_CHG = (background(C_ADD),
348
+ background(C_SUB),
349
+ background(C_CHG))
350
+
351
+ C_NONE = color_codes["none"]
352
+ colors = (C_ADD, C_SUB, C_CHG, C_NONE)
353
+
354
+ s = replace_all({'\0+': C_ADD,
355
+ '\0-': C_SUB,
356
+ '\0^': C_CHG,
357
+ '\1': C_NONE,
358
+ '\t': ' '}, s)
359
+
360
+ if self.highlight:
361
+ return s
362
+
363
+ if not self.show_all_spaces:
364
+ # If there's a change consisting entirely of whitespace,
365
+ # don't color it.
366
+ return re.sub("\033\\[[01];3([123])m(\\s+)(\033\\[)",
367
+ "\033[7;3\\1m\\2\\3", s)
368
+
369
+ def will_see_coloredspace(i, s):
370
+ while i < len(s) and s[i].isspace():
371
+ i += 1
372
+ if i < len(s) and s[i] == '\033':
373
+ return False
374
+ return True
375
+
376
+ n_s = []
377
+ in_color = False
378
+ seen_coloredspace = False
379
+ for i, c in enumerate(s):
380
+ if len(n_s) > 6 and n_s[-1] == "m":
381
+ ns_end = "".join(n_s[-7:])
382
+ for color in colors:
383
+ if ns_end.endswith(color):
384
+ if color != in_color:
385
+ seen_coloredspace = False
386
+ in_color = color
387
+ if ns_end.endswith(C_NONE):
388
+ in_color = False
389
+
390
+ if ((c.isspace() and in_color and
391
+ (self.show_all_spaces or not (seen_coloredspace or
392
+ will_see_coloredspace(i, s))))):
393
+ n_s.extend([C_NONE, background(in_color), c, C_NONE, in_color])
394
+ else:
395
+ if in_color:
396
+ seen_coloredspace = True
397
+ n_s.append(c)
398
+
399
+ joined = "".join(n_s)
400
+
401
+ return joined
402
+
403
+
404
+ def simple_colorize(s, chosen_color):
405
+ return "%s%s%s" % (color_codes[chosen_color], s, color_codes["none"])
406
+
407
+ def replace_all(replacements, string):
408
+ for search, replace in replacements.items():
409
+ string = string.replace(search, replace)
410
+ return string
411
+
412
+ class MultipleOption(Option):
413
+ ACTIONS = Option.ACTIONS + ("extend",)
414
+ STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
415
+ TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
416
+ ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",)
417
+
418
+ def take_action(self, action, dest, opt, value, values, parser):
419
+ if action == "extend":
420
+ values.ensure_value(dest, []).append(value)
421
+ else:
422
+ Option.take_action(self, action, dest, opt, value, values, parser)
423
+
424
+
425
+ def start():
426
+ # If you change any of these, also update README.
427
+ parser = OptionParser(usage="usage: %prog [options] left_file right_file",
428
+ version="icdiff version %s" % __version__,
429
+ description="Show differences between files in a "
430
+ "two column view.",
431
+ option_class=MultipleOption)
432
+ parser.add_option("--cols", default=None,
433
+ help="specify the width of the screen. Autodetection is "
434
+ "Unix only")
435
+ parser.add_option("--encoding", default="utf-8",
436
+ help="specify the file encoding; defaults to utf8")
437
+ parser.add_option("--head", default=0,
438
+ help="consider only the first N lines of each file")
439
+ parser.add_option("--highlight", default=False,
440
+ action="store_true",
441
+ help="color by changing the background color instead of "
442
+ "the foreground color. Very fast, ugly, displays all "
443
+ "changes")
444
+ parser.add_option("-L", "--label",
445
+ action="extend",
446
+ type="string",
447
+ dest='labels',
448
+ help="override file labels with arbitrary tags. "
449
+ "Use twice, one for each file")
450
+ parser.add_option("--line-numbers", default=False,
451
+ action="store_true",
452
+ help="generate output with line numbers")
453
+ parser.add_option("--no-bold", default=False,
454
+ action="store_true",
455
+ help="use non-bold colors; recommended for with solarized")
456
+ parser.add_option("--no-headers", default=False,
457
+ action="store_true",
458
+ help="don't label the left and right sides "
459
+ "with their file names")
460
+ parser.add_option("--output-encoding", default="utf-8",
461
+ help="specify the output encoding; defaults to utf8")
462
+ parser.add_option("--recursive", default=False,
463
+ action="store_true",
464
+ help="recursively compare subdirectories")
465
+ parser.add_option("--show-all-spaces", default=False,
466
+ action="store_true",
467
+ help="color all non-matching whitespace including "
468
+ "that which is not needed for drawing the eye to "
469
+ "changes. Slow, ugly, displays all changes")
470
+ parser.add_option("-u", "--patch", default=True,
471
+ action="store_true",
472
+ help="generate patch. This is always true, "
473
+ "and only exists for compatibility")
474
+ parser.add_option("-U", "--unified", "--numlines", default=5,
475
+ metavar="NUM",
476
+ help="how many lines of context to print; "
477
+ "can't be combined with --whole-file")
478
+ parser.add_option("--whole-file", default=False,
479
+ action="store_true",
480
+ help="show the whole file instead of just changed "
481
+ "lines and context")
482
+
483
+ (options, args) = parser.parse_args()
484
+
485
+ if len(args) != 2:
486
+ parser.print_help()
487
+ sys.exit()
488
+
489
+ a, b = args
490
+
491
+ if not options.cols:
492
+ def ioctl_GWINSZ(fd):
493
+ try:
494
+ import fcntl
495
+ import termios
496
+ import struct
497
+ cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,
498
+ '1234'))
499
+ except Exception:
500
+ return None
501
+ return cr
502
+ cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
503
+ if cr:
504
+ options.cols = cr[1]
505
+ else:
506
+ options.cols = 80
507
+
508
+ if options.recursive:
509
+ diff_recursively(options, a, b)
510
+ else:
511
+ diff_files(options, a, b)
512
+
513
+ def codec_print(s, options):
514
+ s = "%s\n" % s
515
+ if hasattr(sys.stdout, "buffer"):
516
+ sys.stdout.buffer.write(s.encode(options.output_encoding))
517
+ else:
518
+ sys.stdout.write(s.encode(options.output_encoding))
519
+
520
+
521
+ def diff_recursively(options, a, b):
522
+ def print_meta(s):
523
+ codec_print(simple_colorize(s, "magenta"), options)
524
+
525
+ if os.path.isfile(a) and os.path.isfile(b):
526
+ if not filecmp.cmp(a, b, shallow=False):
527
+ diff_files(options, a, b)
528
+
529
+ elif os.path.isdir(a) and os.path.isdir(b):
530
+ a_contents = set(os.listdir(a))
531
+ b_contents = set(os.listdir(b))
532
+
533
+ for child in sorted(a_contents.union(b_contents)):
534
+ if child not in b_contents:
535
+ print_meta("Only in %s: %s" % (a, child))
536
+ elif child not in a_contents:
537
+ print_meta("Only in %s: %s" % (b, child))
538
+ else:
539
+ diff_recursively(options,
540
+ os.path.join(a, child),
541
+ os.path.join(b, child))
542
+ elif os.path.isdir(a) and os.path.isfile(b):
543
+ print_meta("File %s is a directory while %s is a file" % (a, b))
544
+
545
+ elif os.path.isfile(a) and os.path.isdir(b):
546
+ print_meta("File %s is a file while %s is a directory" % (a, b))
547
+
548
+ def read_file(fname, options):
549
+ try:
550
+ with codecs.open(fname, encoding=options.encoding, mode="rb") as inf:
551
+ return inf.readlines()
552
+ except UnicodeDecodeError as e:
553
+ codec_print(
554
+ "error: file '%s' not valid with encoding '%s': <%s> at %s-%s." %
555
+ (fname, options.encoding, e.reason, e.start, e.end), options)
556
+ raise
557
+
558
+
559
+ def diff_files(options, a, b):
560
+ if options.labels:
561
+ if len(options.labels) == 2:
562
+ headers = options.labels
563
+ else:
564
+ codec_print("error: to use arbitrary file labels, "
565
+ "specify -L twice.", options)
566
+ return
567
+ else:
568
+ headers = a, b
569
+ if options.no_headers:
570
+ headers = None, None
571
+
572
+ head = int(options.head)
573
+
574
+ for x in [a, b]:
575
+ if os.path.isdir(x):
576
+ codec_print("error: %s is a directory; did you mean to "
577
+ "pass --recursive?" % x, optoins)
578
+ return
579
+ try:
580
+ lines_a = read_file(a, options)
581
+ lines_b = read_file(b, options)
582
+ except UnicodeDecodeError:
583
+ return
584
+
585
+ if head != 0:
586
+ lines_a = lines_a[:head]
587
+ lines_b = lines_b[:head]
588
+
589
+ cd = ConsoleDiff(cols=int(options.cols),
590
+ show_all_spaces=options.show_all_spaces,
591
+ highlight=options.highlight,
592
+ no_bold=options.no_bold,
593
+ line_numbers=options.line_numbers)
594
+ for line in cd.make_table(
595
+ lines_a, lines_b, headers[0], headers[1],
596
+ context=(not options.whole_file),
597
+ numlines=int(options.unified)):
598
+ codec_print(line, options)
599
+ sys.stdout.flush()
600
+
601
+ if __name__ == "__main__":
602
+ try:
603
+ start()
604
+ except KeyboardInterrupt:
605
+ pass
606
+ except IOError as e:
607
+ if e.errno == errno.EPIPE:
608
+ pass
609
+ else:
610
+ raise