diff --git a/gertty/alembic/versions/254ac5fc3941_attach_comments_to_files.py b/gertty/alembic/versions/254ac5fc3941_attach_comments_to_files.py new file mode 100644 index 0000000..f807629 --- /dev/null +++ b/gertty/alembic/versions/254ac5fc3941_attach_comments_to_files.py @@ -0,0 +1,64 @@ +"""attach comments to files + +Revision ID: 254ac5fc3941 +Revises: 50344aecd1c2 +Create Date: 2015-04-13 15:52:07.104397 + +""" + +# revision identifiers, used by Alembic. +revision = '254ac5fc3941' +down_revision = '50344aecd1c2' + +import sys +import warnings + +from alembic import op +import sqlalchemy as sa + +from gertty.dbsupport import sqlite_alter_columns, sqlite_drop_columns + + +def upgrade(): + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + op.add_column('comment', sa.Column('file_key', sa.Integer())) + sqlite_alter_columns('comment', [ + sa.Column('file_key', sa.Integer(), sa.ForeignKey('file.key')) + ]) + + update_query = sa.text('update comment set file_key=:file_key where key=:key') + file_query = sa.text('select f.key from file f where f.revision_key=:revision_key and f.path=:path') + + file_insert_query = sa.text('insert into file (key, revision_key, path, old_path, status, inserted, deleted) ' + ' values (NULL, :revision_key, :path, NULL, NULL, NULL, NULL)') + + conn = op.get_bind() + + countres = conn.execute('select count(*) from comment') + comments = countres.fetchone()[0] + + comment_res = conn.execute('select p.name, c.number, c.status, r.key, r.number, m.file, m.key ' + 'from project p, change c, revision r, comment m ' + 'where m.revision_key=r.key and r.change_key=c.key and ' + 'c.project_key=p.key order by p.name') + + count = 0 + for (pname, cnumber, cstatus, rkey, rnumber, mfile, mkey) in comment_res.fetchall(): + count += 1 + sys.stdout.write('Comment %s / %s\r' % (count, comments)) + sys.stdout.flush() + + file_res = conn.execute(file_query, revision_key=rkey, path=mfile) + file_key = file_res.fetchone() + if not file_key: + conn.execute(file_insert_query, revision_key=rkey, path=mfile) + file_res = conn.execute(file_query, revision_key=rkey, path=mfile) + file_key = file_res.fetchone() + fkey = file_key[0] + file_res = conn.execute(update_query, file_key=fkey, key=mkey) + sqlite_drop_columns('comment', ['revision_key', 'file']) + print + +def downgrade(): + pass diff --git a/gertty/db.py b/gertty/db.py index 418d45c..eb579db 100644 --- a/gertty/db.py +++ b/gertty/db.py @@ -95,12 +95,11 @@ message_table = Table( comment_table = Table( 'comment', metadata, Column('key', Integer, primary_key=True), - Column('revision_key', Integer, ForeignKey("revision.key"), index=True), + Column('file_key', Integer, ForeignKey("file.key"), index=True), Column('account_key', Integer, ForeignKey("account.key"), index=True), Column('id', String(255), index=True), #, unique=True, nullable=False), Column('in_reply_to', String(255)), Column('created', DateTime, index=True, nullable=False), - Column('file', Text, nullable=False), Column('parent', Boolean, nullable=False), Column('line', Integer), Column('message', Text, nullable=False), @@ -347,15 +346,6 @@ class Revision(object): session.flush() return m - def createComment(self, *args, **kw): - session = Session.object_session(self) - args = [self] + list(args) - c = Comment(*args, **kw) - self.comments.append(c) - session.add(c) - session.flush() - return c - def createPendingCherryPick(self, *args, **kw): session = Session.object_session(self) args = [self] + list(args) @@ -372,8 +362,17 @@ class Revision(object): self.files.append(f) session.add(f) session.flush() + if hasattr(self, '_file_cache'): + self._file_cache[f.path] = f return f + def getFile(self, path): + if not hasattr(self, '_file_cache'): + self._file_cache = {} + for f in self.files: + self._file_cache[f.path] = f + return self._file_cache.get(path, None) + def getPendingMessage(self): for m in self.messages: if m.pending: @@ -410,13 +409,12 @@ class Message(object): return author_name class Comment(object): - def __init__(self, revision, id, author, in_reply_to, created, file, parent, line, message, draft=False): - self.revision_key = revision.key + def __init__(self, file, id, author, in_reply_to, created, parent, line, message, draft=False): + self.file_key = file.key self.account_key = author.key self.id = id self.in_reply_to = in_reply_to self.created = created - self.file = file self.parent = parent self.line = line self.message = message @@ -489,7 +487,22 @@ class File(object): break post = ''.join(post) mid = '{%s => %s}' % (self.old_path[start:0-end+1], self.path[start:0-end+1]) - return pre + mid + post + if pre and post: + mid = '{%s => %s}' % (self.old_path[start:0-end+1], + self.path[start:0-end+1]) + return pre + mid + post + else: + return '%s => %s' % (self.old_path, self.path) + + def createComment(self, *args, **kw): + session = Session.object_session(self) + args = [self] + list(args) + c = Comment(*args, **kw) + self.comments.append(c) + session.add(c) + session.flush() + return c + mapper(Account, account_table) mapper(Project, project_table, properties=dict( @@ -535,20 +548,22 @@ mapper(Change, change_table, properties=dict( )) mapper(Revision, revision_table, properties=dict( messages=relationship(Message, backref='revision'), - comments=relationship(Comment, backref='revision', - order_by=(comment_table.c.line, - comment_table.c.created)), - draft_comments=relationship(Comment, - primaryjoin=and_(revision_table.c.key==comment_table.c.revision_key, - comment_table.c.draft==True), - order_by=(comment_table.c.line, - comment_table.c.created)), files=relationship(File, backref='revision'), pending_cherry_picks=relationship(PendingCherryPick, backref='revision'), )) mapper(Message, message_table, properties=dict( author=relationship(Account))) -mapper(File, file_table) +mapper(File, file_table, properties=dict( + comments=relationship(Comment, backref='file', + order_by=(comment_table.c.line, + comment_table.c.created)), + draft_comments=relationship(Comment, + primaryjoin=and_(file_table.c.key==comment_table.c.file_key, + comment_table.c.draft==True), + order_by=(comment_table.c.line, + comment_table.c.created)), + )) + mapper(Comment, comment_table, properties=dict( author=relationship(Account))) mapper(Label, label_table) @@ -748,6 +763,12 @@ class DatabaseSession(object): except sqlalchemy.orm.exc.NoResultFound: return None + def getFile(self, key): + try: + return self.session().query(File).filter_by(key=key).one() + except sqlalchemy.orm.exc.NoResultFound: + return None + def getComment(self, key): try: return self.session().query(Comment).filter_by(key=key).one() diff --git a/gertty/dbsupport.py b/gertty/dbsupport.py index 45182af..ff94b28 100644 --- a/gertty/dbsupport.py +++ b/gertty/dbsupport.py @@ -133,6 +133,22 @@ def sqlite_drop_columns(table_name, drop_columns): new_columns.append(col_copy) for key in meta.tables[table_name].foreign_keys: + # If this is a single column constraint for a dropped column, + # don't copy it. + if isinstance(key.constraint.columns, sqlalchemy.sql.base.ColumnCollection): + # This is needed for SQLAlchemy >= 1.0.4 + columns = [c.name for c in key.constraint.columns] + else: + # This is needed for SQLAlchemy <= 0.9.9. This is + # backwards compat code just in case someone updates + # Gertty without updating SQLAlchemy. This is simple + # enough to check and will hopefully avoid leaving the + # user's db in an inconsistent state. Remove this after + # Gertty 1.2.0. + columns = key.constraint.columns + if (len(columns)==1 and columns[0] in drop_columns): + continue + # Otherwise, recreate the constraint. constraint = key.constraint con_copy = constraint.copy() new_columns.append(con_copy) diff --git a/gertty/gitrepo.py b/gertty/gitrepo.py index 3599db3..c11474e 100644 --- a/gertty/gitrepo.py +++ b/gertty/gitrepo.py @@ -170,6 +170,8 @@ class DiffFile(object): def __init__(self): self.newname = 'Unknown File' self.oldname = 'Unknown File' + self.old_empty = False + self.new_empty = False self.chunks = [] self.current_chunk = None self.old_lineno = 0 @@ -389,8 +391,10 @@ class Repo(object): # f.newname = diff_context.b_path if diff_context.new_file: f.oldname = 'Empty file' + f.old_empty = True if diff_context.deleted_file: f.newname = 'Empty file' + f.new_empty = True files.append(f) if diff_context.rename_from: f.oldname = diff_context.rename_from @@ -468,6 +472,16 @@ class Repo(object): continue if not last_line: raise Exception("Unhandled line: %s" % line) + if not diff_context.diff: + # There is no diff, possibly because this is simply a + # rename. Include context lines so that comments may + # appear. + newc = repo.commit(new) + blob = newc.tree[f.newname] + f.old_lineno = 1 + f.new_lineno = 1 + for line in blob.data_stream.read().splitlines(): + f.addContextLine(line) f.finalize() return files @@ -479,7 +493,10 @@ class Repo(object): f.new_lineno = 1 repo = git.Repo(self.path) newc = repo.commit(new) - blob = newc.tree[path] + try: + blob = newc.tree[path] + except KeyError: + return None for line in blob.data_stream.read().splitlines(): f.addContextLine(line) f.finalize() diff --git a/gertty/search/parser.py b/gertty/search/parser.py index d2e4600..9548908 100644 --- a/gertty/search/parser.py +++ b/gertty/search/parser.py @@ -298,11 +298,13 @@ def SearchParser(): def p_file_term(p): '''file_term : OP_FILE string''' if p[2].startswith('^'): - p[0] = or_(func.matches(p[2], gertty.db.file_table.c.path), - func.matches(p[2], gertty.db.file_table.c.old_path)) + p[0] = and_(or_(func.matches(p[2], gertty.db.file_table.c.path), + func.matches(p[2], gertty.db.file_table.c.old_path)), + gertty.db.file_table.c.status is not None) else: - p[0] = or_(gertty.db.file_table.c.path == p[2], - gertty.db.file_table.c.old_path == p[2]) + p[0] = and_(or_(gertty.db.file_table.c.path == p[2], + gertty.db.file_table.c.old_path == p[2]), + gertty.db.file_table.c.status is not None) def p_status_term(p): '''status_term : OP_STATUS string''' diff --git a/gertty/sync.py b/gertty/sync.py index 63d6c24..ae22849 100644 --- a/gertty/sync.py +++ b/gertty/sync.py @@ -618,16 +618,21 @@ class SyncChangeTask(Task): parent_commits.add(revision.parent) result.updateRelatedChanges(session, change) - filemap = {} + f = revision.getFile('/COMMIT_MSG') + if f is None: + f = revision.createFile('/COMMIT_MSG', None, + None, None, None) for remote_path, remote_file in remote_revision['files'].items(): - if remote_file.get('binary'): - inserted = deleted = None - else: - inserted = remote_file.get('lines_inserted', 0) - deleted = remote_file.get('lines_deleted', 0) - f = revision.createFile(remote_path, remote_file.get('status', 'M'), - remote_file.get('old_path'), inserted, deleted) - filemap[remote_path] = f + f = revision.getFile(remote_path) + if f is None: + if remote_file.get('binary'): + inserted = deleted = None + else: + inserted = remote_file.get('lines_inserted', 0) + deleted = remote_file.get('lines_deleted', 0) + f = revision.createFile(remote_path, remote_file.get('status', 'M'), + remote_file.get('old_path'), + inserted, deleted) remote_comments_data = remote_revision['_gertty_remote_comments_data'] for remote_file, remote_comments in remote_comments_data.items(): @@ -643,11 +648,12 @@ class SyncChangeTask(Task): parent = False if remote_comment.get('side', '') == 'PARENT': parent = True - comment = revision.createComment(remote_comment['id'], account, - remote_comment.get('in_reply_to'), - created, - remote_file, parent, remote_comment.get('line'), - remote_comment['message']) + fileobj = revision.getFile(remote_file) + comment = fileobj.createComment(remote_comment['id'], account, + remote_comment.get('in_reply_to'), + created, + parent, remote_comment.get('line'), + remote_comment['message']) self.log.info("Created new comment %s for revision %s in local DB.", comment.key, revision.key) else: @@ -1124,21 +1130,20 @@ class UploadReviewTask(Task): for approval in change.draft_approvals: data['labels'][approval.category] = approval.value session.delete(approval) - if revision.draft_comments: - data['comments'] = {} - last_file = None - comment_list = [] - for comment in revision.draft_comments: - if comment.file != last_file: - last_file = comment.file - comment_list = [] - data['comments'][comment.file] = comment_list - d = dict(line=comment.line, - message=comment.message) - if comment.parent: - d['side'] = 'PARENT' - comment_list.append(d) - session.delete(comment) + comments = {} + for file in revision.files: + if file.draft_comments: + comment_list = [] + for comment in file.draft_comments: + d = dict(line=comment.line, + message=comment.message) + if comment.parent: + d['side'] = 'PARENT' + comment_list.append(d) + session.delete(comment) + comments[file.path] = comment_list + if comments: + data['comments'] = comments session.delete(message) # Inside db session for rollback sync.post('changes/%s/revisions/%s/review' % (change.id, revision.commit), diff --git a/gertty/view/change.py b/gertty/view/change.py index 31fe316..659714f 100644 --- a/gertty/view/change.py +++ b/gertty/view/change.py @@ -237,6 +237,8 @@ class RevisionRow(urwid.WidgetWrap): total_added = 0 total_removed = 0 for rfile in revision.files: + if rfile.status is None: + continue added = rfile.inserted or 0 removed = rfile.deleted or 0 total_added += added @@ -279,13 +281,13 @@ class RevisionRow(urwid.WidgetWrap): def update(self, revision): line = [('revision-name', 'Patch Set %s ' % revision.number), ('revision-commit', revision.commit)] - num_drafts = len(revision.draft_comments) + num_drafts = sum([len(f.draft_comments) for f in revision.files]) if num_drafts: pending_message = revision.getPendingMessage() if not pending_message: line.append(('revision-drafts', ' (%s draft%s)' % ( num_drafts, num_drafts>1 and 's' or ''))) - num_comments = len(revision.comments) - num_drafts + num_comments = sum([len(f.comments) for f in revision.files]) - num_drafts if num_comments: line.append(('revision-comments', ' (%s inline comment%s)' % ( num_comments, num_comments>1 and 's' or ''))) diff --git a/gertty/view/diff.py b/gertty/view/diff.py index 4b792ff..21e9b64 100644 --- a/gertty/view/diff.py +++ b/gertty/view/diff.py @@ -84,17 +84,16 @@ class PatchsetDialog(urwid.WidgetWrap): return old, new class LineContext(object): - def __init__(self, old_revision_key, new_revision_key, - old_revision_num, new_revision_num, - old_fn, new_fn, old_ln, new_ln): - self.old_revision_key = old_revision_key - self.new_revision_key = new_revision_key - self.old_revision_num = old_revision_num - self.new_revision_num = new_revision_num + def __init__(self, old_file_key, new_file_key, + old_fn, new_fn, old_ln, new_ln, + header=False): + self.old_file_key = old_file_key + self.new_file_key = new_file_key self.old_fn = old_fn self.new_fn = new_fn self.old_ln = old_ln self.new_ln = new_ln + self.header = header class BaseDiffCommentEdit(urwid.Columns): pass @@ -172,20 +171,33 @@ class BaseDiffView(urwid.WidgetWrap): del self._w.contents[:] with self.app.db.getSession() as session: new_revision = session.getRevision(self.new_revision_key) + old_comments = [] + new_comments = [] + self.old_file_keys = {} + self.new_file_keys = {} if self.old_revision_key is not None: old_revision = session.getRevision(self.old_revision_key) self.old_revision_num = old_revision.number old_str = 'patchset %s' % self.old_revision_num self.base_commit = old_revision.commit - old_comments = old_revision.comments + for f in old_revision.files: + old_comments += f.comments + self.old_file_keys[f.path] = f.key show_old_commit = True else: old_revision = None self.old_revision_num = None old_str = 'base' self.base_commit = new_revision.parent - old_comments = [] show_old_commit = False + # The old files are the same as the new files since we + # are diffing from base -> change, however, we should + # use the old file names for file lookup. + for f in new_revision.files: + if f.old_path: + self.old_file_keys[f.old_path] = f.key + else: + self.old_file_keys[f.path] = f.key self.title = u'Diff of %s change %s from %s to patchset %s' % ( new_revision.change.project.name, new_revision.change.number, @@ -194,19 +206,25 @@ class BaseDiffView(urwid.WidgetWrap): self.change_key = new_revision.change.key self.project_name = new_revision.change.project.name self.commit = new_revision.commit + for f in new_revision.files: + new_comments += f.comments + self.new_file_keys[f.path] = f.key comment_lists = {} comment_filenames = set() - for comment in new_revision.comments: + for comment in new_comments: + path = comment.file.path if comment.parent: if old_revision: # we're not looking at the base continue key = 'old' + if comment.file.old_path: + path = comment.file.old_path else: key = 'new' if comment.draft: key += 'draft' key += '-' + str(comment.line) - key += '-' + str(comment.file) + key += '-' + path comment_list = comment_lists.get(key, []) if comment.draft: message = comment.message @@ -215,15 +233,16 @@ class BaseDiffView(urwid.WidgetWrap): ('comment', u': '+comment.message)] comment_list.append((comment.key, message)) comment_lists[key] = comment_list - comment_filenames.add(comment.file) + comment_filenames.add(path) for comment in old_comments: if comment.parent: continue + path = comment.file.path key = 'old' if comment.draft: key += 'draft' key += '-' + str(comment.line) - key += '-' + str(comment.file) + key += '-' + path comment_list = comment_lists.get(key, []) if comment.draft: message = comment.message @@ -232,7 +251,7 @@ class BaseDiffView(urwid.WidgetWrap): ('comment', u': '+comment.message)] comment_list.append((comment.key, message)) comment_lists[key] = comment_list - comment_filenames.add(comment.file) + comment_filenames.add(path) repo = self.app.getRepo(self.project_name) self._w.contents.append((self.app.header, ('pack', 1))) self.file_reminder = self.makeFileReminder() @@ -250,7 +269,10 @@ class BaseDiffView(urwid.WidgetWrap): # that contain the full text. for filename in comment_filenames: diff = repo.getFile(self.base_commit, self.commit, filename) - diffs.append(diff) + if diff: + diffs.append(diff) + else: + self.log.debug("Unable to find file %s in commit %s" % (filename, self.commit)) for i, diff in enumerate(diffs): if i > 0: lines.append(urwid.Text('')) @@ -297,6 +319,11 @@ class BaseDiffView(urwid.WidgetWrap): oldnew = gitrepo.OLD else: oldnew = gitrepo.NEW + file_diffs = self.file_diffs[oldnew] + if path not in file_diffs: + self.log.error("Unable to display comment: %s" % key) + del comment_lists[key] + continue diff = self.file_diffs[oldnew][path] for chunk in diff.chunks: if (chunk.range[oldnew][gitrepo.START] <= lineno and @@ -341,6 +368,21 @@ class BaseDiffView(urwid.WidgetWrap): else: chunk.button.update() + def makeContext(self, diff, old_ln, new_ln, header=False): + old_key = None + new_key = None + if not diff.old_empty: + if diff.oldname in self.old_file_keys: + old_key = self.old_file_keys[diff.oldname] + elif diff.newname in self.old_file_keys: + old_key = self.old_file_keys[diff.newname] + if not diff.new_empty: + new_key = self.new_file_keys[diff.newname] + return LineContext( + old_key, new_key, + diff.oldname, diff.newname, + old_ln, new_ln, header) + def makeLines(self, diff, lines_to_add, comment_lists): raise NotImplementedError @@ -431,28 +473,25 @@ class BaseDiffView(urwid.WidgetWrap): session.delete(comment) def saveComment(self, context, text, new=True): - if (not new) and (not context.old_revision_num): + if (not new) and (not self.old_revision_num): parent = True - revision_key = context.new_revision_key else: parent = False - if new: - revision_key = context.new_revision_key - else: - revision_key = context.old_revision_key if new: line_num = context.new_ln - filename = context.new_fn + file_key = context.new_file_key else: line_num = context.old_ln - filename = context.old_fn + file_key = context.old_file_key + if file_key is None: + raise Exception("Comment is not associated with a file") with self.app.db.getSession() as session: - revision = session.getRevision(revision_key) + fileojb = session.getFile(file_key) account = session.getAccountByUsername(self.app.config.username) - comment = revision.createComment(None, account, None, - datetime.datetime.utcnow(), - filename, parent, - line_num, text, draft=True) + comment = fileojb.createComment(None, account, None, + datetime.datetime.utcnow(), + parent, + line_num, text, draft=True) key = comment.key return key diff --git a/gertty/view/side_diff.py b/gertty/view/side_diff.py index 493f65c..cb56985 100644 --- a/gertty/view/side_diff.py +++ b/gertty/view/side_diff.py @@ -17,7 +17,6 @@ import urwid from gertty import keymap from gertty.view.diff import BaseDiffComment, BaseDiffCommentEdit, BaseDiffLine from gertty.view.diff import BaseFileHeader, BaseFileReminder, BaseDiffView -from gertty.view.diff import LineContext LN_COL_WIDTH = 5 @@ -32,20 +31,32 @@ class SideDiffCommentEdit(BaseDiffCommentEdit): 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', LN_COL_WIDTH, False))) - self.contents.append((urwid.AttrMap(self.old, 'draft-comment'), ('weight', 1, False))) + if context.old_ln is not None or context.header: + self.contents.append((urwid.AttrMap(self.old, 'draft-comment'), ('weight', 1, False))) + else: + self.contents.append((urwid.Text(u''), ('weight', 1, False))) self.contents.append((urwid.Text(u''), ('given', LN_COL_WIDTH, False))) - self.contents.append((urwid.AttrMap(self.new, 'draft-comment'), ('weight', 1, False))) - self.focus_position = 3 + if context.new_ln is not None or context.header: + self.contents.append((urwid.AttrMap(self.new, 'draft-comment'), ('weight', 1, False))) + else: + self.contents.append((urwid.Text(u''), ('weight', 1, False))) + if context.new_ln is not None or context.header: + self.focus_position = 3 + else: + self.focus_position = 1 def keypress(self, size, key): r = super(SideDiffCommentEdit, self).keypress(size, key) commands = self.app.config.keymap.getCommands(r) if ((keymap.NEXT_SELECTABLE in commands) or (keymap.PREV_SELECTABLE in commands)): - if self.focus_position == 3: - self.focus_position = 1 - else: - self.focus_position = 3 + if ((self.context.old_ln is not None and + self.context.new_ln is not None) or + self.context.header): + if self.focus_position == 3: + self.focus_position = 1 + else: + self.focus_position = 3 return None return r @@ -117,11 +128,7 @@ 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]) + context = self.makeContext(diff, old[0], new[0]) lines.append(SideDiffLine(self.app, context, old, new, callback=self.onSelect)) # see if there are any comments for this line @@ -159,11 +166,7 @@ class SideDiffView(BaseDiffView): return SideFileReminder() 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) + context = self.makeContext(diff, None, None, header=True) lines = [] lines.append(SideFileHeader(self.app, context, diff.oldname, diff.newname, callback=self.onSelect)) diff --git a/gertty/view/unified_diff.py b/gertty/view/unified_diff.py index 714a30a..5c00f79 100644 --- a/gertty/view/unified_diff.py +++ b/gertty/view/unified_diff.py @@ -18,7 +18,6 @@ import urwid from gertty import gitrepo from gertty.view.diff import BaseDiffCommentEdit, BaseDiffComment, BaseDiffLine from gertty.view.diff import BaseFileHeader, BaseFileReminder, BaseDiffView -from gertty.view.diff import LineContext LN_COL_WIDTH = 5 @@ -121,11 +120,7 @@ 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]) + context = self.makeContext(diff, old[0], new[0]) if context.old_ln is not None: lines.append(UnifiedDiffLine(self.app, context, gitrepo.OLD, old, new, callback=self.onSelect)) @@ -169,11 +164,7 @@ class UnifiedDiffView(BaseDiffView): return UnifiedFileReminder() 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) + context = self.makeContext(diff, None, None, header=True) lines = [] lines.append(UnifiedFileHeader(self.app, context, gitrepo.OLD, diff.oldname, diff.newname,