From 227b6a0add5b4047c89a744cb8e33317cd1648a9 Mon Sep 17 00:00:00 2001 From: "James E. Blair" Date: Sun, 4 May 2014 13:32:28 -0700 Subject: [PATCH] Expand context as needed to include all comments Use methods that can be re-used to support manually expanding context by the user. Also fix a s/old/new/ typo bug. Change-Id: I5b247204b959add9fbfd51af7e508d3d07b7c001 --- gertty/gitrepo.py | 42 +++++++++++++++++++++++ gertty/view/diff.py | 81 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 118 insertions(+), 5 deletions(-) diff --git a/gertty/gitrepo.py b/gertty/gitrepo.py index 09501f1..02e022a 100644 --- a/gertty/gitrepo.py +++ b/gertty/gitrepo.py @@ -19,12 +19,53 @@ import re import git +OLD = 0 +NEW = 1 +START = 0 +END = 1 +LINENO = 0 +LINE = 1 + class DiffChunk(object): def __init__(self): self.oldlines = [] self.newlines = [] self.first = False self.last = False + self.lines = [] + self.calcRange() + + def __repr__(self): + return '<%s old lines %s-%s / new lines %s-%s>' % ( + self.__class__.__name__, + self.range[OLD][START], self.range[OLD][END], + self.range[NEW][START], self.range[NEW][END]) + + def calcRange(self): + self.range = [[0, 0], + [0, 0]] + for l in self.lines: + if self.range[OLD][START] == 0 and l[OLD][LINENO] is not None: + self.range[OLD][START] = l[OLD][LINENO] + if self.range[NEW][START] == 0 and l[NEW][LINENO] is not None: + self.range[NEW][START] = l[NEW][LINENO] + if (self.range[OLD][START] != 0 and + self.range[NEW][START] != 0): + break + + for l in self.lines[::-1]: + if self.range[OLD][END] == 0 and l[OLD][LINENO] is not None: + self.range[OLD][END] = l[OLD][LINENO] + if self.range[NEW][END] == 0 and l[NEW][LINENO] is not None: + self.range[NEW][END] = l[NEW][LINENO] + if (self.range[OLD][END] != 0 and + self.range[NEW][END] != 0): + break + + def indexOfLine(self, oldnew, lineno): + for i, l in enumerate(self.lines): + if l[oldnew][LINENO] == lineno: + return i class DiffContextChunk(DiffChunk): context = True @@ -52,6 +93,7 @@ class DiffFile(object): else: self.chunks[-1].last = False self.current_chunk.last = True + self.current_chunk.calcRange() self.chunks.append(self.current_chunk) self.current_chunk = None diff --git a/gertty/view/diff.py b/gertty/view/diff.py index 2d768cc..9ae47dd 100644 --- a/gertty/view/diff.py +++ b/gertty/view/diff.py @@ -18,6 +18,7 @@ import logging import urwid from gertty import mywid +from gertty import gitrepo class LineContext(object): def __init__(self, old_revision_key, new_revision_key, @@ -102,6 +103,14 @@ class DiffLine(urwid.Button): } self._w = urwid.AttrMap(col, None, focus_map=map) +class DiffContextButton(urwid.Button): + def selectable(self): + return False #TODO: change + + def __init__(self, chunk): + super(DiffContextButton, self).__init__('...') + self.chunk = chunk + class DiffView(urwid.WidgetWrap): help = mywid.GLOBAL_HELP + """ This Screen @@ -146,11 +155,14 @@ This Screen repo = self.app.getRepo(self.project_name) self._w.contents.append((app.header, ('pack', 1))) self._w.contents.append((urwid.Divider(), ('pack', 1))) - lines = [] + lines = [] # The initial set of lines to display + self.file_diffs = [{}, {}] # Mapping of fn -> DiffFile object (old, new) # this is a list of files: for i, diff in enumerate(repo.diff(self.parent, self.commit)): if i > 0: lines.append(urwid.Text('')) + self.file_diffs[gitrepo.OLD][diff.oldname] = diff + self.file_diffs[gitrepo.NEW][diff.newname] = diff lines.append(urwid.Columns([ urwid.Text(diff.oldname), urwid.Text(diff.newname)])) @@ -158,19 +170,78 @@ This Screen if chunk.context: if not chunk.first: lines += self.makeLines(diff, chunk.lines[:10], comment_lists) - lines.append(urwid.Text('...')) + del chunk.lines[:10] + button = DiffContextButton(chunk) + chunk.button = button + lines.append(button) if not chunk.last: lines += self.makeLines(diff, chunk.lines[-10:], comment_lists) + del chunk.lines[-10:] + chunk.calcRange() + if not chunk.lines: + lines.remove(button) else: lines += self.makeLines(diff, chunk.lines, comment_lists) - if comment_lists: - self.log.debug("Undisplayed comments: %s" % comment_lists) listwalker = urwid.SimpleFocusListWalker(lines) self.listbox = urwid.ListBox(listwalker) self._w.contents.append((self.listbox, ('weight', 1))) self.old_focus = 2 self.draft_comments = [] self._w.set_focus(self.old_focus) + self.handleUndisplayedComments(comment_lists) + + def handleUndisplayedComments(self, comment_lists): + # Handle comments that landed outside our default diff context + import time + lastlen = 0 + while comment_lists: + if len(comment_lists.keys()) == lastlen: + self.log.error("Unable to display all comments: %s" % comment_lists) + return + lastlen = len(comment_lists.keys()) + key = comment_lists.keys()[0] + kind, lineno, path = key.split('-', 2) + lineno = int(lineno) + if kind.startswith('old'): + oldnew = gitrepo.OLD + else: + oldnew = gitrepo.NEW + diff = self.file_diffs[oldnew][path] + for chunk in diff.chunks: + if (chunk.range[oldnew][gitrepo.START] <= lineno and + chunk.range[oldnew][gitrepo.END] >= lineno): + i = chunk.indexOfLine(oldnew, lineno) + if i < (len(chunk.lines) / 2): + from_start = True + else: + from_start = False + if chunk.first and from_start: + from_start = False + if chunk.last and (not from_start): + from_start = True + if from_start: + self.expandChunk(diff, chunk, comment_lists, from_start=i+10) + else: + self.expandChunk(diff, chunk, comment_lists, from_end=i-10) + break + + def expandChunk(self, diff, chunk, comment_lists, from_start=None, from_end=None): + self.log.debug("Expand chunk %s %s %s" % (chunk, from_start, from_end)) + add_lines = [] + if from_start is not None: + index = self.listbox.body.index(chunk.button) + add_lines = chunk.lines[:from_start] + del chunk.lines[:from_start] + if from_end is not None: + index = self.listbox.body.index(chunk.button)+1 + add_lines = chunk.lines[from_end:] + del chunk.lines[from_end:] + if add_lines: + lines = self.makeLines(diff, add_lines, comment_lists) + self.listbox.body[index:index] = lines + chunk.calcRange() + if not chunk.lines: + self.listbox.body.remove(chunk.button) def makeLines(self, diff, lines_to_add, comment_lists): lines = [] @@ -198,7 +269,7 @@ This Screen # see if there are any draft comments for this line key = 'olddraft-%s-%s' % (old[0], diff.oldname) old_list = comment_lists.pop(key, []) - key = 'newdraft-%s-%s' % (old[0], diff.oldname) + key = 'newdraft-%s-%s' % (new[0], diff.newname) new_list = comment_lists.pop(key, []) while old_list or new_list: old_comment_key = new_comment_key = None