Skip to content

Commit

Permalink
Merge pull request #12 from pysquared/master
Browse files Browse the repository at this point in the history
A few tidy ups :-)
  • Loading branch information
jeffkaufman committed Dec 8, 2014
2 parents 94ba182 + 3dbf4cc commit c95177e
Showing 1 changed file with 59 additions and 61 deletions.
120 changes: 59 additions & 61 deletions icdiff
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class ConsoleDiff(object):
"""

def __init__(self,tabsize=8,wrapcolumn=None,linejunk=None,
def __init__(self, tabsize=8, wrapcolumn=None, linejunk=None,
charjunk=difflib.IS_CHARACTER_JUNK, cols=80,
line_numbers=False,
show_all_spaces=False,
Expand All @@ -52,7 +52,7 @@ class ConsoleDiff(object):
tabsize -- tab stop spacing, defaults to 8.
wrapcolumn -- column number where lines are broken and wrapped,
defaults to None where lines are not wrapped.
linejunk,charjunk -- keyword arguments passed into ndiff() (used by
linejunk, charjunk -- keyword arguments passed into ndiff() (used by
ConsoleDiff() to generate the side by side differences). See
ndiff() documentation for argument default values and descriptions.
"""
Expand All @@ -66,16 +66,16 @@ class ConsoleDiff(object):

if wrapcolumn is None:
if not line_numbers:
wrapcolumn = self.cols//2-2
wrapcolumn = self.cols // 2 - 2
else:
wrapcolumn = self.cols//2-10
wrapcolumn = self.cols // 2 - 10

self._wrapcolumn = wrapcolumn
self._linejunk = linejunk
self._charjunk = charjunk


def _tab_newline_replace(self,fromlines,tolines):
def _tab_newline_replace(self, fromlines, tolines):
"""Returns from/to line lists with tabs expanded and newlines removed.
Instead of tab characters being replaced by the number of spaces
Expand All @@ -87,18 +87,18 @@ class ConsoleDiff(object):
"""
def expand_tabs(line):
# hide real spaces
line = line.replace(' ','\0')
line = line.replace(' ', '\0')
# expand tabs into spaces
line = line.expandtabs(self._tabsize)
# relace spaces from expanded tabs back into tab characters
# (we'll replace them with markup after we do differencing)
line = line.replace(' ','\t')
return line.replace('\0',' ').rstrip('\n')
line = line.replace(' ', '\t')
return line.replace('\0', ' ').rstrip('\n')
fromlines = [expand_tabs(line) for line in fromlines]
tolines = [expand_tabs(line) for line in tolines]
return fromlines,tolines
return fromlines, tolines

def _split_line(self,data_list,line_num,text):
def _split_line(self, data_list, line_num, text):
"""Builds list of text lines by splitting text lines at wrap point
This function will determine if the input text line needs to be
Expand All @@ -109,22 +109,21 @@ class ConsoleDiff(object):
"""
# if blank line or context separator, just add it to the output list
if not line_num:
data_list.append((line_num,text))
data_list.append((line_num, text))
return

# if line text doesn't need wrapping, just add it to the output list
size = len(text)
max = self._wrapcolumn
if (size <= max) or ((size -(text.count('\0')*3)) <= max):
data_list.append((line_num,text))
if (size <= self._wrapcolumn) or ((size - (text.count('\0') * 3)) <= self._wrapcolumn):
data_list.append((line_num, text))
return

# scan text looking for the wrap point, keeping track if the wrap
# point is inside markers
i = 0
n = 0
mark = ''
while n < max and i < size:
while n < self._wrapcolumn and i < size:
if text[i] == '\0':
i += 1
mark = text[i]
Expand All @@ -148,61 +147,61 @@ class ConsoleDiff(object):
line2 = '\0' + mark + line2

# tack on first line onto the output list
data_list.append((line_num,line1))
data_list.append((line_num, line1))

# use this routine again to wrap the remaining text
self._split_line(data_list,'>',line2)
self._split_line(data_list, '>', line2)

def _line_wrapper(self,diffs):
def _line_wrapper(self, diffs):
"""Returns iterator that splits (wraps) mdiff text lines"""

# pull from/to data and flags from mdiff iterator
for fromdata,todata,flag in diffs:
for fromdata, todata, flag in diffs:
# check for context separators and pass them through
if flag is None:
yield fromdata,todata,flag
yield fromdata, todata, flag
continue
(fromline,fromtext),(toline,totext) = fromdata,todata
(fromline, fromtext), (toline, totext) = fromdata, todata
# for each from/to line split it at the wrap column to form
# list of text lines.
fromlist,tolist = [],[]
self._split_line(fromlist,fromline,fromtext)
self._split_line(tolist,toline,totext)
fromlist, tolist = [], []
self._split_line(fromlist, fromline, fromtext)
self._split_line(tolist, toline, totext)
# yield from/to line in pairs inserting blank lines as
# necessary when one side has more wrapped lines
while fromlist or tolist:
if fromlist:
fromdata = fromlist.pop(0)
else:
fromdata = ('',' ')
fromdata = ('', ' ')
if tolist:
todata = tolist.pop(0)
else:
todata = ('',' ')
yield fromdata,todata,flag
todata = ('', ' ')
yield fromdata, todata, flag

def _collect_lines(self,diffs):
def _collect_lines(self, diffs):
"""Collects mdiff output into separate lists
Before storing the mdiff from/to data into a list, it is converted
into a single line of text with console markup.
"""

fromlist,tolist,flaglist = [],[],[]
fromlist, tolist, flaglist = [], [], []
# pull from/to data and flags from mdiff style iterator
for fromdata,todata,flag in diffs:
for fromdata, todata, flag in diffs:
try:
# store HTML markup of the lines into the lists
fromlist.append(self._format_line(0,flag,*fromdata))
tolist.append(self._format_line(1,flag,*todata))
fromlist.append(self._format_line(0, flag, *fromdata))
tolist.append(self._format_line(1, flag, *todata))
except TypeError:
# exceptions occur for lines where context separators go
fromlist.append(None)
tolist.append(None)
flaglist.append(flag)
return fromlist,tolist,flaglist
return fromlist, tolist, flaglist

def _format_line(self,side,flag,linenum,text):
def _format_line(self, side, flag, linenum, text):
"""Returns HTML markup of "from" / "to" text lines
side -- 0 or 1 indicating "from" or "to" text
Expand All @@ -211,22 +210,22 @@ class ConsoleDiff(object):
text -- line text to be marked up
"""
try:
id = '%d' % linenum
lid = '%d' % linenum
except TypeError:
# handle blank lines where linenum is '>' or ''
id = ''
lid = ''

text = text.rstrip()

if not self.line_numbers:
return text
return '%s %s' % (self._rpad(id, 8), text)
return '%s %s' % (self._rpad(lid, 8), text)

def _real_len(self, s):
l = 0
in_esc = False
prev = ' '
for c in s.replace('\0+',"").replace('\0-',"").replace('\0^',"").replace('\1',"").replace('\t',' '):
for c in s.replace('\0+', "").replace('\0-', "").replace('\0^', "").replace('\1', "").replace('\t', ' '):
if in_esc:
if c == "m":
in_esc = False
Expand All @@ -246,40 +245,40 @@ class ConsoleDiff(object):
return self._pad(s, field_width) + s

def _pad(self, s, field_width):
return " "*(field_width-self._real_len(s))
return " " * (field_width - self._real_len(s))

def _lpad(self, s, field_width):
target = s + self._pad(s, field_width)
#if self._real_len(target) != field_width:
# print("Warning: bad line %r is not of length %d" % (target, field_width))
return target

def _convert_flags(self,fromlist,tolist,flaglist,context,numlines):
def _convert_flags(self, fromlist, tolist, flaglist, context, numlines):
"""Makes list of "next" links"""

# all anchor names will be generated using the unique "to" prefix

# process change flags, generating middle column of next anchors/links
next_id = ['']*len(flaglist)
next_href = ['']*len(flaglist)
next_id = [''] * len(flaglist)
next_href = [''] * len(flaglist)
num_chg, in_change = 0, False
last = 0
toprefix = ''
for i,flag in enumerate(flaglist):
for i, flag in enumerate(flaglist):
if flag:
if not in_change:
in_change = True
last = i
# at the beginning of a change, drop an anchor a few lines
# (the context lines) before the change for the previous
# link
i = max([0,i-numlines])
next_id[i] = ' id="difflib_chg_%s_%d"' % (toprefix,num_chg)
i = max([0, i - numlines])
next_id[i] = ' id="difflib_chg_%s_%d"' % (toprefix, num_chg)
# at the beginning of a change, drop a link to the next
# change
num_chg += 1
next_href[last] = '<a href="#difflib_chg_%s_%d">n</a>' % (
toprefix,num_chg)
toprefix, num_chg)
else:
in_change = False
# check for cases where there is no content to avoid exceptions
Expand All @@ -299,9 +298,9 @@ class ConsoleDiff(object):
# redo the last link to link to the top
next_href[last] = '<a href="#difflib_chg_%s_top">t</a>' % (toprefix)

return fromlist,tolist,flaglist,next_href,next_id
return fromlist, tolist, flaglist, next_href, next_id

def make_table(self,fromlines,tolines,fromdesc='',todesc='',context=False,
def make_table(self, fromlines, tolines, fromdesc='', todesc='', context=False,
numlines=5):
"""Returns table of side by side comparison with change highlights
Expand All @@ -321,14 +320,14 @@ class ConsoleDiff(object):

# change tabs to spaces before it gets more difficult after we insert
# markkup
fromlines,tolines = self._tab_newline_replace(fromlines,tolines)
fromlines, tolines = self._tab_newline_replace(fromlines, tolines)

# create diffs iterator which generates side by side from/to data
if context:
context_lines = numlines
else:
context_lines = None
diffs = difflib._mdiff(fromlines,tolines,context_lines,linejunk=self._linejunk,
diffs = difflib._mdiff(fromlines, tolines, context_lines, linejunk=self._linejunk,
charjunk=self._charjunk)


Expand All @@ -337,37 +336,37 @@ class ConsoleDiff(object):
diffs = self._line_wrapper(diffs)

# collect up from/to lines and flags into lists (also format the lines)
fromlist,tolist,flaglist = self._collect_lines(diffs)
fromlist, tolist, flaglist = self._collect_lines(diffs)

# process change flags, generating middle column of next anchors/links
fromlist,tolist,flaglist,next_href,next_id = self._convert_flags(
fromlist,tolist,flaglist,context,numlines)
fromlist, tolist, flaglist, next_href, next_id = self._convert_flags(
fromlist, tolist, flaglist, context, numlines)

s = []

if fromdesc or todesc:
s.append((self.colorize(fromdesc, "blue"),
self.colorize(todesc, "blue")))
self.colorize(todesc, "blue")))

for i in range(len(flaglist)):
if flaglist[i] is None:
# mdiff yields None on separator lines; skip the bogus ones
# generated for the first line

if i > 0:
s.append( (self.colorize('---', "blue"),
self.colorize('---', "blue")) )
s.append((self.colorize('---', "blue"),
self.colorize('---', "blue")))
else:
s.append( (fromlist[i], tolist[i]) )
s.append((fromlist[i], tolist[i]))

table_lines = []
for sides in s:
line = []
for side in sides:
line.append(self._lpad(side, self.cols//2-1))
line.append(self._lpad(side, self.cols // 2 - 1))
table_lines.append(" ".join(line))

table_line_string="\n".join(table_lines)
table_line_string = "\n".join(table_lines)

colorized_table_line_string = self.colorize(table_line_string)

Expand All @@ -391,7 +390,6 @@ class ConsoleDiff(object):
"blue_bold": '\033[1;34m',
"magenta_bold": '\033[1;35m',
"cyan_bold": '\033[1;36m',
"none": '\033[m',
}

if self.no_bold:
Expand All @@ -412,7 +410,7 @@ class ConsoleDiff(object):
C_NONE = codes["none"]
colors = (C_ADD, C_SUB, C_CHG, C_NONE)

s = s.replace('\0+', C_ADD).replace('\0-', C_SUB).replace('\0^', C_CHG).replace('\1', C_NONE).replace('\t',' ')
s = s.replace('\0+', C_ADD).replace('\0-', C_SUB).replace('\0^', C_CHG).replace('\1', C_NONE).replace('\t', ' ')

if self.highlight:
return s
Expand Down

0 comments on commit c95177e

Please sign in to comment.