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:
parent
7a71108c60
commit
a44a82bff3
@ -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
|
||||
|
@ -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)))
|
||||
|
Loading…
x
Reference in New Issue
Block a user