From 11bdd67e863a8b108be03843a6621a7f7315869d Mon Sep 17 00:00:00 2001 From: "James E. Blair" Date: Mon, 18 Aug 2014 20:35:33 -0700 Subject: [PATCH] Add unified diff view Refactor commonalities into base diff view, and implement unified and side-by-side diff views. Configurable in the config yaml file. Change-Id: Ia8d9241d04f3e7f480618e7efe1d3792f530e173 --- gertty.yaml-sample | 4 + gertty/config.py | 3 + gertty/view/change.py | 9 +- gertty/view/diff.py | 198 ++++---------------------------- gertty/view/side_diff.py | 207 ++++++++++++++++++++++++++++++++++ gertty/view/unified_diff.py | 217 ++++++++++++++++++++++++++++++++++++ 6 files changed, 457 insertions(+), 181 deletions(-) create mode 100644 gertty/view/side_diff.py create mode 100644 gertty/view/unified_diff.py diff --git a/gertty.yaml-sample b/gertty.yaml-sample index 6942710..ba2636f 100644 --- a/gertty.yaml-sample +++ b/gertty.yaml-sample @@ -37,6 +37,10 @@ commentlinks: # # change-list-query: "status:open not label:Workflow=-1" +# Uncomment the following line to use a unified diff view instead +# of the default side-by-side: +# diff-view: unified + dashboards: - name: "My changes" query: "owner:self status:open" diff --git a/gertty/config.py b/gertty/config.py index f4a9252..ff2a449 100644 --- a/gertty/config.py +++ b/gertty/config.py @@ -90,6 +90,7 @@ class ConfigSchema(object): 'dashboards': self.dashboards, 'reviewkeys': self.reviewkeys, 'change-list-query': str, + 'diff-view': str, }) return schema @@ -144,6 +145,8 @@ class Config(object): self.project_change_list_query = self.config.get('change-list-query', 'status:open') + self.diff_view = self.config.get('diff-view', 'side-by-side') + self.dashboards = OrderedDict() for d in self.config.get('dashboards', []): self.dashboards[d['key']] = d diff --git a/gertty/view/change.py b/gertty/view/change.py index d665eb9..3dc8c8e 100644 --- a/gertty/view/change.py +++ b/gertty/view/change.py @@ -20,7 +20,8 @@ import urwid from gertty import gitrepo from gertty import mywid from gertty import sync -from gertty.view import diff as view_diff +from gertty.view import side_diff as view_side_diff +from gertty.view import unified_diff as view_unified_diff import gertty.view class ReviewDialog(urwid.WidgetWrap): @@ -609,7 +610,11 @@ class ChangeView(urwid.WidgetWrap): return r def diff(self, revision_key): - self.app.changeScreen(view_diff.DiffView(self.app, revision_key)) + if self.app.config.diff_view == 'unified': + screen = view_unified_diff.UnifiedDiffView(self.app, revision_key) + else: + screen = view_side_diff.SideDiffView(self.app, revision_key) + self.app.changeScreen(screen) def reviewKey(self, reviewkey): approvals = {} diff --git a/gertty/view/diff.py b/gertty/view/diff.py index 5b611ce..4c22b85 100644 --- a/gertty/view/diff.py +++ b/gertty/view/diff.py @@ -93,91 +93,20 @@ class LineContext(object): self.old_ln = old_ln self.new_ln = new_ln -class DiffCommentEdit(urwid.Columns): - def __init__(self, context, old_key=None, new_key=None, old=u'', new=u''): - super(DiffCommentEdit, self).__init__([]) - self.context = context - # If we save a comment, the resulting key will be stored here - self.old_key = old_key - self.new_key = new_key - self.old = urwid.Edit(edit_text=old, multiline=True) - self.new = urwid.Edit(edit_text=new, multiline=True) - self.contents.append((urwid.Text(u''), ('given', 4, False))) - self.contents.append((urwid.AttrMap(self.old, 'draft-comment'), ('weight', 1, False))) - self.contents.append((urwid.Text(u''), ('given', 4, False))) - self.contents.append((urwid.AttrMap(self.new, 'draft-comment'), ('weight', 1, False))) - self.focus_position = 3 +class BaseDiffCommentEdit(urwid.Columns): + pass - def keypress(self, size, key): - r = super(DiffCommentEdit, self).keypress(size, key) - if r in ['tab', 'shift tab']: - if self.focus_position == 3: - self.focus_position = 1 - else: - self.focus_position = 3 - return None - return r +class BaseDiffComment(urwid.Columns): + pass -class DiffComment(urwid.Columns): - def __init__(self, context, old, new): - super(DiffComment, self).__init__([]) - self.context = context - oldt = urwid.Text(old) - newt = urwid.Text(new) - if old: - oldt = urwid.AttrMap(oldt, 'comment') - if new: - newt = urwid.AttrMap(newt, 'comment') - self.contents.append((urwid.Text(u''), ('given', 4, False))) - self.contents.append((oldt, ('weight', 1, False))) - self.contents.append((urwid.Text(u''), ('given', 4, False))) - self.contents.append((newt, ('weight', 1, False))) - -class DiffLine(urwid.Button): +class BaseDiffLine(urwid.Button): def selectable(self): return True - def __init__(self, app, context, old, new, callback=None): - super(DiffLine, self).__init__('', on_press=callback) - self.context = context - columns = [] - for (ln, action, line) in (old, new): - if ln is None: - ln = '' - else: - ln = str(ln) - ln_col = urwid.Text(('line-number', ln)) - ln_col.set_wrap_mode('clip') - line_col = urwid.Text(line) - line_col.set_wrap_mode('clip') - if action == '': - line_col = urwid.AttrMap(line_col, 'nonexistent') - columns += [(4, ln_col), line_col] - col = urwid.Columns(columns) - map = {None: 'focused', - 'added-line': 'focused-added-line', - 'added-word': 'focused-added-word', - 'removed-line': 'focused-removed-line', - 'removed-word': 'focused-removed-word', - 'nonexistent': 'focused-nonexistent', - 'line-number': 'focused-line-number', - } - self._w = urwid.AttrMap(col, None, focus_map=map) - -class FileHeader(urwid.Button): +class BaseFileHeader(urwid.Button): def selectable(self): return True - def __init__(self, app, context, old, new, callback=None): - super(FileHeader, self).__init__('', on_press=callback) - self.context = context - col = urwid.Columns([ - urwid.Text(('filename', old)), - urwid.Text(('filename', new))]) - map = {None: 'focused-filename', - 'filename': 'focused-filename'} - self._w = urwid.AttrMap(col, None, focus_map=map) - class DiffContextButton(urwid.WidgetWrap): def selectable(self): return True @@ -214,7 +143,7 @@ class DiffContextButton(urwid.WidgetWrap): def next(self, button): self.view.expandChunk(self.diff, self.chunk, from_end=-10) -class DiffView(urwid.WidgetWrap): +class BaseDiffView(urwid.WidgetWrap): _help = """ Add an inline comment

Select old/new patchsets to diff @@ -224,7 +153,7 @@ class DiffView(urwid.WidgetWrap): return self._help def __init__(self, app, new_revision_key): - super(DiffView, self).__init__(urwid.Pile([])) + super(BaseDiffView, self).__init__(urwid.Pile([])) self.log = logging.getLogger('gertty.view.diff') self.app = app self.old_revision_key = None # Base @@ -404,86 +333,10 @@ class DiffView(urwid.WidgetWrap): chunk.button.update() def makeLines(self, diff, lines_to_add, comment_lists): - lines = [] - for old, new in lines_to_add: - context = LineContext( - self.old_revision_key, self.new_revision_key, - self.old_revision_num, 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.pop(key, []) - key = 'new-%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 - 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.pop(key, []) - 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 - 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)) - return lines + raise NotImplementedError def makeFileHeader(self, diff, comment_lists): - context = LineContext( - self.old_revision_key, self.new_revision_key, - self.old_revision_num, self.new_revision_num, - diff.oldname, diff.newname, - None, None) - lines = [] - lines.append(FileHeader(self.app, context, diff.oldname, diff.newname, - callback=self.onSelect)) - - # see if there are any comments for this file - key = 'old-None-%s' % (diff.oldname,) - old_list = comment_lists.pop(key, []) - key = 'new-None-%s' % (diff.newname,) - new_list = comment_lists.pop(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 file - key = 'olddraft-None-%s' % (diff.oldname,) - old_list = comment_lists.pop(key, []) - key = 'newdraft-None-%s' % (diff.newname,) - new_list = comment_lists.pop(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)) - return lines + raise NotImplementedError def refresh(self): #TODO @@ -491,9 +344,9 @@ class DiffView(urwid.WidgetWrap): def keypress(self, size, key): old_focus = self.listbox.focus - r = super(DiffView, self).keypress(size, key) + r = super(BaseDiffView, self).keypress(size, key) new_focus = self.listbox.focus - if (isinstance(old_focus, DiffCommentEdit) and + if (isinstance(old_focus, BaseDiffCommentEdit) and (old_focus != new_focus or key == 'esc')): self.cleanupEdit(old_focus) if r == 'p': @@ -503,36 +356,23 @@ class DiffView(urwid.WidgetWrap): def mouse_event(self, size, event, button, x, y, focus): old_focus = self.listbox.focus - r = super(DiffView, self).mouse_event(size, event, button, x, y, focus) + r = super(BaseDiffView, self).mouse_event(size, event, button, x, y, focus) new_focus = self.listbox.focus - if old_focus != new_focus and isinstance(old_focus, DiffCommentEdit): + if old_focus != new_focus and isinstance(old_focus, BaseDiffCommentEdit): self.cleanupEdit(old_focus) return r + def makeCommentEdit(self, edit): + raise NotImplementedError + def onSelect(self, button): pos = self.listbox.focus_position - e = DiffCommentEdit(self.listbox.body[pos].context) + e = self.makeCommentEdit(self.listbox.body[pos]) self.listbox.body.insert(pos+1, e) self.listbox.focus_position = pos+1 def cleanupEdit(self, edit): - if edit.old_key: - self.deleteComment(edit.old_key) - edit.old_key = None - if edit.new_key: - self.deleteComment(edit.new_key) - edit.new_key = None - old = edit.old.edit_text.strip() - new = edit.new.edit_text.strip() - if old or new: - if old: - edit.old_key = self.saveComment( - edit.context, old, new=False) - if new: - edit.new_key = self.saveComment( - edit.context, new, new=True) - else: - self.listbox.body.remove(edit) + raise NotImplementedError def deleteComment(self, comment_key): with self.app.db.getSession() as session: diff --git a/gertty/view/side_diff.py b/gertty/view/side_diff.py new file mode 100644 index 0000000..0dd491f --- /dev/null +++ b/gertty/view/side_diff.py @@ -0,0 +1,207 @@ +# Copyright 2014 OpenStack Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import datetime +import logging + +import urwid + +from gertty import mywid +from gertty import gitrepo +from gertty.view.diff import * + +class SideDiffCommentEdit(BaseDiffCommentEdit): + def __init__(self, context, old_key=None, new_key=None, old=u'', new=u''): + super(SideDiffCommentEdit, self).__init__([]) + self.context = context + # If we save a comment, the resulting key will be stored here + self.old_key = old_key + self.new_key = new_key + self.old = urwid.Edit(edit_text=old, multiline=True) + self.new = urwid.Edit(edit_text=new, multiline=True) + self.contents.append((urwid.Text(u''), ('given', 4, False))) + self.contents.append((urwid.AttrMap(self.old, 'draft-comment'), ('weight', 1, False))) + self.contents.append((urwid.Text(u''), ('given', 4, False))) + self.contents.append((urwid.AttrMap(self.new, 'draft-comment'), ('weight', 1, False))) + self.focus_position = 3 + + def keypress(self, size, key): + r = super(SideDiffCommentEdit, self).keypress(size, key) + if r in ['tab', 'shift tab']: + if self.focus_position == 3: + self.focus_position = 1 + else: + self.focus_position = 3 + return None + return r + +class SideDiffComment(BaseDiffComment): + def __init__(self, context, old, new): + super(SideDiffComment, self).__init__([]) + self.context = context + oldt = urwid.Text(old) + newt = urwid.Text(new) + if old: + oldt = urwid.AttrMap(oldt, 'comment') + if new: + newt = urwid.AttrMap(newt, 'comment') + self.contents.append((urwid.Text(u''), ('given', 4, False))) + self.contents.append((oldt, ('weight', 1, False))) + self.contents.append((urwid.Text(u''), ('given', 4, False))) + self.contents.append((newt, ('weight', 1, False))) + +class SideDiffLine(BaseDiffLine): + def __init__(self, app, context, old, new, callback=None): + super(SideDiffLine, self).__init__('', on_press=callback) + self.context = context + columns = [] + for (ln, action, line) in (old, new): + if ln is None: + ln = '' + else: + ln = str(ln) + ln_col = urwid.Text(('line-number', ln)) + ln_col.set_wrap_mode('clip') + line_col = urwid.Text(line) + line_col.set_wrap_mode('clip') + if action == '': + line_col = urwid.AttrMap(line_col, 'nonexistent') + columns += [(4, ln_col), line_col] + col = urwid.Columns(columns) + map = {None: 'focused', + 'added-line': 'focused-added-line', + 'added-word': 'focused-added-word', + 'removed-line': 'focused-removed-line', + 'removed-word': 'focused-removed-word', + 'nonexistent': 'focused-nonexistent', + 'line-number': 'focused-line-number', + } + self._w = urwid.AttrMap(col, None, focus_map=map) + +class SideFileHeader(BaseFileHeader): + def __init__(self, app, context, old, new, callback=None): + super(SideFileHeader, self).__init__('', on_press=callback) + self.context = context + col = urwid.Columns([ + urwid.Text(('filename', old)), + urwid.Text(('filename', new))]) + map = {None: 'focused-filename', + 'filename': 'focused-filename'} + self._w = urwid.AttrMap(col, None, focus_map=map) + + +class SideDiffView(BaseDiffView): + def makeLines(self, diff, lines_to_add, comment_lists): + lines = [] + for old, new in lines_to_add: + context = LineContext( + self.old_revision_key, self.new_revision_key, + self.old_revision_num, self.new_revision_num, + diff.oldname, diff.newname, + old[0], new[0]) + lines.append(SideDiffLine(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.pop(key, []) + key = 'new-%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 + 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(SideDiffComment(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.pop(key, []) + 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 + 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(SideDiffCommentEdit(context, + old_comment_key, + new_comment_key, + old_comment, new_comment)) + return lines + + def makeFileHeader(self, diff, comment_lists): + context = LineContext( + self.old_revision_key, self.new_revision_key, + self.old_revision_num, self.new_revision_num, + diff.oldname, diff.newname, + None, None) + lines = [] + lines.append(SideFileHeader(self.app, context, diff.oldname, diff.newname, + callback=self.onSelect)) + + # see if there are any comments for this file + key = 'old-None-%s' % (diff.oldname,) + old_list = comment_lists.pop(key, []) + key = 'new-None-%s' % (diff.newname,) + new_list = comment_lists.pop(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(SideDiffComment(context, old_comment, new_comment)) + # see if there are any draft comments for this file + key = 'olddraft-None-%s' % (diff.oldname,) + old_list = comment_lists.pop(key, []) + key = 'newdraft-None-%s' % (diff.newname,) + new_list = comment_lists.pop(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(SideDiffCommentEdit(context, + old_comment_key, + new_comment_key, + old_comment, new_comment)) + return lines + + def makeCommentEdit(self, edit): + return SideDiffCommentEdit(edit.context) + + def cleanupEdit(self, edit): + if edit.old_key: + self.deleteComment(edit.old_key) + edit.old_key = None + if edit.new_key: + self.deleteComment(edit.new_key) + edit.new_key = None + old = edit.old.edit_text.strip() + new = edit.new.edit_text.strip() + if old or new: + if old: + edit.old_key = self.saveComment( + edit.context, old, new=False) + if new: + edit.new_key = self.saveComment( + edit.context, new, new=True) + else: + self.listbox.body.remove(edit) diff --git a/gertty/view/unified_diff.py b/gertty/view/unified_diff.py new file mode 100644 index 0000000..899ef95 --- /dev/null +++ b/gertty/view/unified_diff.py @@ -0,0 +1,217 @@ +# Copyright 2014 OpenStack Foundation +# Copyright 2014 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import datetime +import logging + +import urwid + +from gertty import mywid +from gertty import gitrepo +from gertty.view.diff import * + +class UnifiedDiffCommentEdit(BaseDiffCommentEdit): + def __init__(self, context, oldnew, key=None, comment=u''): + super(UnifiedDiffCommentEdit, self).__init__([]) + self.context = context + self.oldnew = oldnew + # If we save a comment, the resulting key will be stored here + self.key = key + self.comment = urwid.Edit(edit_text=comment, multiline=True) + self.contents.append((urwid.Text(u''), ('given', 8, False))) + self.contents.append((urwid.AttrMap(self.comment, 'draft-comment'), + ('weight', 1, False))) + self.focus_position = 1 + +class UnifiedDiffComment(BaseDiffComment): + def __init__(self, context, oldnew, comment): + super(UnifiedDiffComment, self).__init__([]) + self.context = context + text = urwid.AttrMap(urwid.Text(comment), 'comment') + self.contents.append((urwid.Text(u''), ('given', 8, False))) + self.contents.append((text, ('weight', 1, False))) + +class UnifiedDiffLine(BaseDiffLine): + def __init__(self, app, context, oldnew, old, new, callback=None): + super(UnifiedDiffLine, self).__init__('', on_press=callback) + self.context = context + self.oldnew = oldnew + (old_ln, old_action, old_line) = old + (new_ln, new_action, new_line) = new + if old_ln is None: + old_ln = '' + else: + old_ln = str(old_ln) + if new_ln is None: + new_ln = '' + else: + new_ln = str(new_ln) + old_ln_col = urwid.Text(('line-number', old_ln)) + old_ln_col.set_wrap_mode('clip') + new_ln_col = urwid.Text(('line-number', new_ln)) + new_ln_col.set_wrap_mode('clip') + if oldnew == gitrepo.OLD: + action = old_action + line = old_line + columns = [(4, old_ln_col), (4, urwid.Text(u''))] + elif oldnew == gitrepo.NEW: + action = new_action + line = new_line + columns = [(4, urwid.Text(u'')), (4, new_ln_col)] + if new_action == ' ': + columns = [(4, old_ln_col), (4, new_ln_col)] + line_col = urwid.Text(line) + if action == '': + line_col = urwid.AttrMap(line_col, 'nonexistent') + columns += [line_col] + col = urwid.Columns(columns) + map = {None: 'focused', + 'added-line': 'focused-added-line', + 'added-word': 'focused-added-word', + 'removed-line': 'focused-removed-line', + 'removed-word': 'focused-removed-word', + 'nonexistent': 'focused-nonexistent', + 'line-number': 'focused-line-number', + } + self._w = urwid.AttrMap(col, None, focus_map=map) + +class UnifiedFileHeader(BaseFileHeader): + def __init__(self, app, context, oldnew, old, new, callback=None): + super(UnifiedFileHeader, self).__init__('', on_press=callback) + self.context = context + self.oldnew = oldnew + if oldnew == gitrepo.OLD: + col = urwid.Columns([ + urwid.Text(('filename', old))]) + elif oldnew == gitrepo.NEW: + col = urwid.Columns([ + (4, urwid.Text(u'')), + urwid.Text(('filename', new))]) + map = {None: 'focused-filename', + 'filename': 'focused-filename'} + self._w = urwid.AttrMap(col, None, focus_map=map) + +class UnifiedDiffView(BaseDiffView): + def makeLines(self, diff, lines_to_add, comment_lists): + lines = [] + for old, new in lines_to_add: + context = LineContext( + self.old_revision_key, self.new_revision_key, + self.old_revision_num, self.new_revision_num, + diff.oldname, diff.newname, + old[0], new[0]) + if context.old_ln is not None: + lines.append(UnifiedDiffLine(self.app, context, gitrepo.OLD, 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.pop(key, []) + while old_list: + (old_comment_key, old_comment) = old_list.pop(0) + lines.append(UnifiedDiffComment(context, gitrepo.OLD, old_comment)) + # see if there are any draft comments for this line + key = 'olddraft-%s-%s' % (old[0], diff.oldname) + old_list = comment_lists.pop(key, []) + while old_list: + (old_comment_key, old_comment) = old_list.pop(0) + lines.append(UnifiedDiffCommentEdit(context, + gitrepo.OLD, + old_comment_key, + old_comment)) + # new line + if context.new_ln is not None and new[1] != ' ': + lines.append(UnifiedDiffLine(self.app, context, gitrepo.NEW, old, new, + callback=self.onSelect)) + # see if there are any comments for this line + key = 'new-%s-%s' % (new[0], diff.newname) + new_list = comment_lists.pop(key, []) + while new_list: + (new_comment_key, new_comment) = new_list.pop(0) + lines.append(UnifiedDiffComment(context, gitrepo.NEW, new_comment)) + # see if there are any draft comments for this line + key = 'newdraft-%s-%s' % (new[0], diff.newname) + new_list = comment_lists.pop(key, []) + while new_list: + (new_comment_key, new_comment) = new_list.pop(0) + lines.append(UnifiedDiffCommentEdit(context, + gitrepo.NEW, + new_comment_key, + new_comment)) + return lines + + def makeFileHeader(self, diff, comment_lists): + context = LineContext( + self.old_revision_key, self.new_revision_key, + self.old_revision_num, self.new_revision_num, + diff.oldname, diff.newname, + None, None) + lines = [] + lines.append(UnifiedFileHeader(self.app, context, gitrepo.OLD, + diff.oldname, diff.newname, + callback=self.onSelect)) + # see if there are any comments for this file + key = 'old-None-%s' % (diff.oldname,) + old_list = comment_lists.pop(key, []) + while old_list: + (old_comment_key, old_comment) = old_list.pop(0) + lines.append(UnifiedDiffComment(context, gitrepo.OLD, old_comment)) + # see if there are any draft comments for this file + key = 'olddraft-None-%s' % (diff.oldname,) + old_list = comment_lists.pop(key, []) + while old_list: + (old_comment_key, old_comment) = old_list.pop(0) + lines.append(UnifiedDiffCommentEdit(context, + gitrepo.OLD, + old_comment_key, + old_comment)) + # new line + lines.append(UnifiedFileHeader(self.app, context, gitrepo.NEW, + diff.oldname, diff.newname, + callback=self.onSelect)) + + # see if there are any comments for this file + key = 'new-None-%s' % (diff.newname,) + new_list = comment_lists.pop(key, []) + while new_list: + (new_comment_key, new_comment) = new_list.pop(0) + lines.append(UnifiedDiffComment(context, gitrepo.NEW, new_comment)) + # see if there are any draft comments for this file + key = 'newdraft-None-%s' % (diff.newname,) + new_list = comment_lists.pop(key, []) + while new_list: + (new_comment_key, new_comment) = new_list.pop(0) + lines.append(UnifiedDiffCommentEdit(context, + gitrepo.NEW, + new_comment_key, + new_comment)) + return lines + + def makeCommentEdit(self, edit): + return UnifiedDiffCommentEdit(edit.context, + edit.oldnew) + + def cleanupEdit(self, edit): + if edit.key: + self.deleteComment(edit.key) + edit.key = None + comment = edit.comment.edit_text.strip() + if comment: + new = False + if edit.oldnew == gitrepo.NEW: + new = True + edit.key = self.saveComment( + edit.context, comment, new=new) + else: + self.listbox.body.remove(edit)