Refactor diff calculation to facilitate more context

Create groups of diff chunks and context chunks.  In a subsequent
change we can use that to better control the displayed context.

Change-Id: I75858d002e9a9fff809c91cfced81c6022d86196
This commit is contained in:
James E. Blair 2014-05-03 16:51:30 -07:00
parent 7a71108c60
commit a44a82bff3
2 changed files with 111 additions and 65 deletions

View File

@ -19,12 +19,74 @@ import re
import git
class DiffContextChunk(object):
context = True
def __init__(self):
self.oldlines = []
self.newlines = []
class DiffChangedChunk(object):
context = False
def __init__(self):
self.oldlines = []
self.newlines = []
class DiffFile(object):
def __init__(self):
self.newname = None
self.oldname = None
self.oldlines = []
self.newlines = []
self.chunks = []
self.current_chunk = None
self.old_lineno = 0
self.new_lineno = 0
self.offset = 0
def finalize(self):
if not self.current_chunk:
return
self.current_chunk.lines = zip(self.current_chunk.oldlines,
self.current_chunk.newlines)
self.chunks.append(self.current_chunk)
self.current_chunk = None
def addDiffLines(self, old, new):
if (self.current_chunk and
not isinstance(self.current_chunk, DiffChangedChunk)):
self.finalize()
if not self.current_chunk:
self.current_chunk = DiffChangedChunk()
for l in old:
self.current_chunk.oldlines.append((self.old_lineno, '-', l))
self.old_lineno += 1
self.offset -= 1
for l in new:
self.current_chunk.newlines.append((self.new_lineno, '+', l))
self.new_lineno += 1
self.offset += 1
while self.offset > 0:
self.current_chunk.oldlines.append((None, '', ''))
self.offset -= 1
while self.offset < 0:
self.current_chunk.newlines.append((None, '', ''))
self.offset += 1
def addNewLine(self, line):
if (self.current_chunk and
not isinstance(self.current_chunk, DiffChangedChunk)):
self.finalize()
if not self.current_chunk:
self.current_chunk = DiffChangedChunk()
def addContextLine(self, line):
if (self.current_chunk and
not isinstance(self.current_chunk, DiffContextChunk)):
self.finalize()
if not self.current_chunk:
self.current_chunk = DiffContextChunk()
self.current_chunk.oldlines.append((self.old_lineno, ' ', line))
self.current_chunk.newlines.append((self.new_lineno, ' ', line))
self.old_lineno += 1
self.new_lineno += 1
class GitCheckoutError(Exception):
def __init__(self, msg):
@ -63,7 +125,8 @@ class Repo(object):
ret.append(x.split('\t'))
return ret
def intraline_diff(self, old, new):
def intralineDiff(self, old, new):
# takes a list of old lines and a list of new lines
prevline = None
prevstyle = None
output_old = []
@ -138,15 +201,13 @@ class Repo(object):
newc = repo.commit(new)
files = []
for diff_context in oldc.diff(newc, create_patch=True, U=context):
# Each iteration of this is a file
f = DiffFile()
files.append(f)
if diff_context.rename_from:
f.oldname = diff_context.rename_from
if diff_context.rename_to:
f.newname = diff_context.rename_to
old_lineno = 0
new_lineno = 0
offset = 0
oldchunk = []
newchunk = []
prev_key = ''
@ -167,8 +228,8 @@ class Repo(object):
#socket.sendall(line)
m = self.header_re.match(line)
#socket.sendall(str(m.groups()))
old_lineno = int(m.group(1))
new_lineno = int(m.group(3))
f.old_lineno = int(m.group(1))
f.new_lineno = int(m.group(3))
continue
if not line:
if prev_key != '\\':
@ -204,29 +265,14 @@ class Repo(object):
prev_key = ''
# end of chunk
if oldchunk or newchunk:
oldchunk, newchunk = self.intraline_diff(oldchunk, newchunk)
for l in oldchunk:
f.oldlines.append((old_lineno, '-', l))
old_lineno += 1
offset -= 1
for l in newchunk:
f.newlines.append((new_lineno, '+', l))
new_lineno += 1
offset += 1
oldchunk, newchunk = self.intralineDiff(oldchunk, newchunk)
f.addDiffLines(oldchunk, newchunk)
oldchunk = []
newchunk = []
while offset > 0:
f.oldlines.append((None, '', ''))
offset -= 1
while offset < 0:
f.newlines.append((None, '', ''))
offset += 1
if key == ' ':
f.oldlines.append((old_lineno, ' ', rest))
f.newlines.append((new_lineno, ' ', rest))
old_lineno += 1
new_lineno += 1
f.addContextLine(rest)
continue
if not last_line:
raise Exception("Unhandled line: %s" % line)
f.finalize()
return files

View File

@ -154,44 +154,44 @@ This Screen
lines.append(urwid.Columns([
urwid.Text(diff.oldname),
urwid.Text(diff.newname)]))
for i, old in enumerate(diff.oldlines):
new = diff.newlines[i]
context = LineContext(
None, self.new_revision_key,
None, self.new_revision_num,
diff.oldname, diff.newname,
old[0], new[0])
lines.append(DiffLine(self.app, context, old, new,
callback=self.onSelect))
# see if there are any comments for this line
key = 'old-%s-%s' % (old[0], diff.oldname)
old_list = comment_lists.get(key, [])
key = 'new-%s-%s' % (new[0], diff.newname)
new_list = comment_lists.get(key, [])
while old_list or new_list:
old_comment_key = new_comment_key = None
old_comment = new_comment = u''
if old_list:
(old_comment_key, old_comment) = old_list.pop(0)
if new_list:
(new_comment_key, new_comment) = new_list.pop(0)
lines.append(DiffComment(context, old_comment, new_comment))
# see if there are any draft comments for this line
key = 'olddraft-%s-%s' % (old[0], diff.oldname)
old_list = comment_lists.get(key, [])
key = 'newdraft-%s-%s' % (old[0], diff.oldname)
new_list = comment_lists.get(key, [])
while old_list or new_list:
old_comment_key = new_comment_key = None
old_comment = new_comment = u''
if old_list:
(old_comment_key, old_comment) = old_list.pop(0)
if new_list:
(new_comment_key, new_comment) = new_list.pop(0)
lines.append(DiffCommentEdit(context,
old_comment_key,
new_comment_key,
old_comment, new_comment))
for chunk in diff.chunks:
for old, new in chunk.lines:
context = LineContext(
None, self.new_revision_key,
None, self.new_revision_num,
diff.oldname, diff.newname,
old[0], new[0])
lines.append(DiffLine(self.app, context, old, new,
callback=self.onSelect))
# see if there are any comments for this line
key = 'old-%s-%s' % (old[0], diff.oldname)
old_list = comment_lists.get(key, [])
key = 'new-%s-%s' % (new[0], diff.newname)
new_list = comment_lists.get(key, [])
while old_list or new_list:
old_comment_key = new_comment_key = None
old_comment = new_comment = u''
if old_list:
(old_comment_key, old_comment) = old_list.pop(0)
if new_list:
(new_comment_key, new_comment) = new_list.pop(0)
lines.append(DiffComment(context, old_comment, new_comment))
# see if there are any draft comments for this line
key = 'olddraft-%s-%s' % (old[0], diff.oldname)
old_list = comment_lists.get(key, [])
key = 'newdraft-%s-%s' % (old[0], diff.oldname)
new_list = comment_lists.get(key, [])
while old_list or new_list:
old_comment_key = new_comment_key = None
old_comment = new_comment = u''
if old_list:
(old_comment_key, old_comment) = old_list.pop(0)
if new_list:
(new_comment_key, new_comment) = new_list.pop(0)
lines.append(DiffCommentEdit(context,
old_comment_key,
new_comment_key,
old_comment, new_comment))
listwalker = urwid.SimpleFocusListWalker(lines)
self.listbox = urwid.ListBox(listwalker)
self._w.contents.append((self.listbox, ('weight', 1)))