WIP: support inline comment threads
Change-Id: I570c4a85953511c1f5d74653df9d2c4aae45a474
This commit is contained in:
parent
559bcfdb33
commit
8e95ab8f94
95
gertty/db.py
95
gertty/db.py
@ -138,6 +138,7 @@ comment_table = Table(
|
|||||||
Column('line', Integer),
|
Column('line', Integer),
|
||||||
Column('message', Text, nullable=False),
|
Column('message', Text, nullable=False),
|
||||||
Column('draft', Boolean, index=True, nullable=False),
|
Column('draft', Boolean, index=True, nullable=False),
|
||||||
|
Column('unresolved', Boolean, index=True, nullable=False),
|
||||||
Column('robot_id', String(255)),
|
Column('robot_id', String(255)),
|
||||||
Column('robot_run_id', String(255)),
|
Column('robot_run_id', String(255)),
|
||||||
Column('url', Text()),
|
Column('url', Text()),
|
||||||
@ -317,6 +318,32 @@ class Topic(object):
|
|||||||
self.projects.remove(project)
|
self.projects.remove(project)
|
||||||
session.flush()
|
session.flush()
|
||||||
|
|
||||||
|
class Thread:
|
||||||
|
def __init__(self):
|
||||||
|
self.origin_id = None
|
||||||
|
self.ids = set()
|
||||||
|
self.key = None
|
||||||
|
self.comments = []
|
||||||
|
self.unresolved = False
|
||||||
|
self.patchset = None
|
||||||
|
self.path = None
|
||||||
|
self.line = None
|
||||||
|
self.has_draft = False
|
||||||
|
|
||||||
|
def addComment(self, path, ps, message, comment):
|
||||||
|
self.unresolved = comment.unresolved
|
||||||
|
if comment.id:
|
||||||
|
self.ids.add(comment.id)
|
||||||
|
self.comments.append(comment)
|
||||||
|
if self.key is None:
|
||||||
|
self.origin_id = comment.id
|
||||||
|
self.key = (path, ps, comment.line or 0, comment.message)
|
||||||
|
self.line = comment.line or ''
|
||||||
|
self.patchset = ps
|
||||||
|
self.path = path
|
||||||
|
if comment.draft:
|
||||||
|
self.has_draft = True
|
||||||
|
|
||||||
class Change(object):
|
class Change(object):
|
||||||
def __init__(self, project, id, owner, number, branch, change_id,
|
def __init__(self, project, id, owner, number, branch, change_id,
|
||||||
subject, created, updated, status, topic=None,
|
subject, created, updated, status, topic=None,
|
||||||
@ -361,6 +388,71 @@ class Change(object):
|
|||||||
self._updateApprovalCache()
|
self._updateApprovalCache()
|
||||||
return self._approval_cache.get(category, 0)
|
return self._approval_cache.get(category, 0)
|
||||||
|
|
||||||
|
def createComment(self, timestamp, revision, fileobj,
|
||||||
|
account, in_reply_to, parent, line, text):
|
||||||
|
draft_message = revision.getPendingMessage()
|
||||||
|
if not draft_message:
|
||||||
|
draft_message = revision.getDraftMessage()
|
||||||
|
if not draft_message:
|
||||||
|
draft_message = revision.createMessage(None, account,
|
||||||
|
timestamp,
|
||||||
|
'', draft=True)
|
||||||
|
for other_comment in self.getCommentsForMessage(draft_message):
|
||||||
|
if other_comment.draft:
|
||||||
|
other_comment.created = timestamp
|
||||||
|
draft_message.created = timestamp
|
||||||
|
comment = fileobj.createComment(None, account, in_reply_to,
|
||||||
|
timestamp,
|
||||||
|
parent,
|
||||||
|
line, text, draft=True)
|
||||||
|
return comment.key
|
||||||
|
|
||||||
|
def getThreads(self):
|
||||||
|
if not hasattr(self, '_threads'):
|
||||||
|
self.makeThreads()
|
||||||
|
return self._threads
|
||||||
|
|
||||||
|
def getCommentsForMessage(self, target):
|
||||||
|
messages = {}
|
||||||
|
for message in self.messages:
|
||||||
|
messages[(message.author.id, message.created)] = message
|
||||||
|
|
||||||
|
ret = []
|
||||||
|
for revno, revision in enumerate(self.revisions):
|
||||||
|
for file in revision.files:
|
||||||
|
for comment in file.comments:
|
||||||
|
found = messages.get((comment.author.id, comment.created))
|
||||||
|
if found is target:
|
||||||
|
ret.append(comment)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def makeThreads(self):
|
||||||
|
threads = []
|
||||||
|
|
||||||
|
messages = {}
|
||||||
|
for message in self.messages:
|
||||||
|
messages[(message.author.id, message.created)] = message
|
||||||
|
|
||||||
|
for revno, revision in enumerate(self.revisions):
|
||||||
|
for file in revision.files:
|
||||||
|
for comment in file.comments:
|
||||||
|
message = messages.get((comment.author.id, comment.created))
|
||||||
|
if not message:
|
||||||
|
continue
|
||||||
|
comment_ps = revno + 1
|
||||||
|
thread = None
|
||||||
|
for t in threads:
|
||||||
|
if comment.in_reply_to in t.ids:
|
||||||
|
thread = t
|
||||||
|
if not thread:
|
||||||
|
thread = Thread()
|
||||||
|
threads.append(thread)
|
||||||
|
thread.addComment(comment.file.path, comment_ps, message, comment)
|
||||||
|
comment._thread = thread
|
||||||
|
comment._message = message
|
||||||
|
threads.sort(key=lambda t: t.key)
|
||||||
|
self._threads = threads
|
||||||
|
|
||||||
def _updateApprovalCache(self):
|
def _updateApprovalCache(self):
|
||||||
cat_min = {}
|
cat_min = {}
|
||||||
cat_max = {}
|
cat_max = {}
|
||||||
@ -586,7 +678,7 @@ class Message(object):
|
|||||||
|
|
||||||
class Comment(object):
|
class Comment(object):
|
||||||
def __init__(self, file, id, author, in_reply_to, created, parent, line, message, draft=False,
|
def __init__(self, file, id, author, in_reply_to, created, parent, line, message, draft=False,
|
||||||
robot_id=None, robot_run_id=None, url=None):
|
robot_id=None, robot_run_id=None, url=None, unresolved=False):
|
||||||
self.file_key = file.key
|
self.file_key = file.key
|
||||||
self.account_key = author.key
|
self.account_key = author.key
|
||||||
self.id = id
|
self.id = id
|
||||||
@ -599,6 +691,7 @@ class Comment(object):
|
|||||||
self.robot_id = robot_id
|
self.robot_id = robot_id
|
||||||
self.robot_run_id = robot_run_id
|
self.robot_run_id = robot_run_id
|
||||||
self.url = url
|
self.url = url
|
||||||
|
self.unresolved = unresolved
|
||||||
|
|
||||||
class Label(object):
|
class Label(object):
|
||||||
def __init__(self, change, category, value, description):
|
def __init__(self, change, category, value, description):
|
||||||
|
@ -63,6 +63,23 @@ DEFAULT_PALETTE={
|
|||||||
'focused-revision-commit': ['dark blue,standout', ''],
|
'focused-revision-commit': ['dark blue,standout', ''],
|
||||||
'focused-revision-comments': ['default,standout', ''],
|
'focused-revision-comments': ['default,standout', ''],
|
||||||
'focused-revision-drafts': ['dark red,standout', ''],
|
'focused-revision-drafts': ['dark red,standout', ''],
|
||||||
|
|
||||||
|
'comment-thread-unresolved': ['yellow', ''],
|
||||||
|
'comment-thread-unresolved-name': ['yellow', ''],
|
||||||
|
'comment-thread-unresolved-header': ['brown', ''],
|
||||||
|
'comment-thread-unresolved-own-name': ['light cyan', ''],
|
||||||
|
'comment-thread-unresolved-own-header': ['dark cyan', ''],
|
||||||
|
'comment-thread-resolved': ['dark gray', ''],
|
||||||
|
'comment-thread-resolved-name': ['dark gray', ''],
|
||||||
|
'comment-thread-resolved-header': ['dark gray', ''],
|
||||||
|
'comment-thread-resolved-own-name': ['dark gray', ''],
|
||||||
|
'comment-thread-resolved-own-header': ['dark gray', ''],
|
||||||
|
|
||||||
|
'comment-thread-checkbox': ['dark magenta', ''],
|
||||||
|
'focused-comment-thread-checkbox': ['light magenta', ''],
|
||||||
|
'comment-thread-button': ['dark magenta', ''],
|
||||||
|
'focused-comment-thread-button': ['light magenta', ''],
|
||||||
|
|
||||||
'change-message-name': ['yellow', ''],
|
'change-message-name': ['yellow', ''],
|
||||||
'change-message-own-name': ['light cyan', ''],
|
'change-message-own-name': ['light cyan', ''],
|
||||||
'change-message-header': ['brown', ''],
|
'change-message-header': ['brown', ''],
|
||||||
|
@ -798,6 +798,10 @@ class SyncChangeTask(Task):
|
|||||||
username=remote_comment['author'].get('username'),
|
username=remote_comment['author'].get('username'),
|
||||||
email=remote_comment['author'].get('email'))
|
email=remote_comment['author'].get('email'))
|
||||||
comment = session.getCommentByID(remote_comment['id'])
|
comment = session.getCommentByID(remote_comment['id'])
|
||||||
|
# Unresolved can't really change, but we may
|
||||||
|
# have old data before we started storing
|
||||||
|
# unresolved.
|
||||||
|
unresolved = remote_comment.get('unresolved', False)
|
||||||
if not comment:
|
if not comment:
|
||||||
# Normalize updated -> created
|
# Normalize updated -> created
|
||||||
created = dateutil.parser.parse(remote_comment['updated'])
|
created = dateutil.parser.parse(remote_comment['updated'])
|
||||||
@ -814,12 +818,15 @@ class SyncChangeTask(Task):
|
|||||||
remote_comment['message'],
|
remote_comment['message'],
|
||||||
robot_id = remote_comment.get('robot_id'),
|
robot_id = remote_comment.get('robot_id'),
|
||||||
robot_run_id = remote_comment.get('robot_run_id'),
|
robot_run_id = remote_comment.get('robot_run_id'),
|
||||||
url = remote_comment.get('url'))
|
url = remote_comment.get('url'),
|
||||||
|
unresolved = unresolved)
|
||||||
self.log.info("Created new comment %s for revision %s in local DB.",
|
self.log.info("Created new comment %s for revision %s in local DB.",
|
||||||
comment.key, revision.key)
|
comment.key, revision.key)
|
||||||
else:
|
else:
|
||||||
if comment.author != account:
|
if comment.author != account:
|
||||||
comment.author = account
|
comment.author = account
|
||||||
|
if comment.unresolved != unresolved:
|
||||||
|
comment.unresolved = unresolved
|
||||||
if remote_revision.get('_gertty_remote_checks_data'):
|
if remote_revision.get('_gertty_remote_checks_data'):
|
||||||
self._updateChecks(session, change, revision, remote_revision['_gertty_remote_checks_data'])
|
self._updateChecks(session, change, revision, remote_revision['_gertty_remote_checks_data'])
|
||||||
# End revisions
|
# End revisions
|
||||||
@ -1391,9 +1398,12 @@ class UploadReviewTask(Task):
|
|||||||
comment_list = []
|
comment_list = []
|
||||||
for comment in file.draft_comments:
|
for comment in file.draft_comments:
|
||||||
d = dict(line=comment.line,
|
d = dict(line=comment.line,
|
||||||
|
unresolved=comment.unresolved,
|
||||||
message=comment.message)
|
message=comment.message)
|
||||||
if comment.parent:
|
if comment.parent:
|
||||||
d['side'] = 'PARENT'
|
d['side'] = 'PARENT'
|
||||||
|
if comment.in_reply_to:
|
||||||
|
d['in_reply_to'] = comment.in_reply_to
|
||||||
comment_list.append(d)
|
comment_list.append(d)
|
||||||
session.delete(comment)
|
session.delete(comment)
|
||||||
comments[file.path] = comment_list
|
comments[file.path] = comment_list
|
||||||
|
@ -394,6 +394,249 @@ class ChangeButton(urwid.Button):
|
|||||||
except gertty.view.DisplayError as e:
|
except gertty.view.DisplayError as e:
|
||||||
self.change_view.app.error(e.message)
|
self.change_view.app.error(e.message)
|
||||||
|
|
||||||
|
class ThreadCommentBox(mywid.HyperText):
|
||||||
|
def __init__(self, change_view, change, thread, message, comment):
|
||||||
|
super().__init__('')
|
||||||
|
self.change_view = change_view
|
||||||
|
self.app = change_view.app
|
||||||
|
self.refresh(change, thread, message, comment)
|
||||||
|
|
||||||
|
def selectable(self):
|
||||||
|
return len(self.selectable_items) > 0
|
||||||
|
|
||||||
|
def refresh(self, change, thread, message, comment):
|
||||||
|
self.comment_key = comment.key
|
||||||
|
self.message_created = message.created
|
||||||
|
self.message_author = message.author_name
|
||||||
|
self.message_text = message.message
|
||||||
|
created = self.app.time(message.created)
|
||||||
|
unresolved = thread.unresolved
|
||||||
|
if thread.has_draft:
|
||||||
|
unresolved = True
|
||||||
|
if unresolved:
|
||||||
|
style = 'comment-thread-unresolved'
|
||||||
|
else:
|
||||||
|
style = 'comment-thread-resolved'
|
||||||
|
if self.app.isOwnAccount(message.author):
|
||||||
|
name_style = f'{style}-own-name'
|
||||||
|
header_style = f'{style}-own-header'
|
||||||
|
reviewer_string = message.author_name
|
||||||
|
else:
|
||||||
|
name_style = f'{style}-name'
|
||||||
|
header_style = f'{style}-header'
|
||||||
|
if message.author.email:
|
||||||
|
reviewer_string = "%s <%s>" % (
|
||||||
|
message.author_name,
|
||||||
|
message.author.email)
|
||||||
|
else:
|
||||||
|
reviewer_string = message.author_name
|
||||||
|
|
||||||
|
text = [(name_style, reviewer_string),
|
||||||
|
(header_style, f': Patch Set {message.revision.number}'),
|
||||||
|
(header_style, created.strftime(' (%Y-%m-%d %H:%M:%S%z)'))]
|
||||||
|
if message.draft and not message.pending:
|
||||||
|
text.append(('change-message-draft', ' (draft)'))
|
||||||
|
|
||||||
|
#comment_text = ['\n'.join(lines)]
|
||||||
|
#for commentlink in self.app.config.commentlinks:
|
||||||
|
# comment_text = commentlink.run(self.app, comment_text)
|
||||||
|
|
||||||
|
text.append('\n')
|
||||||
|
text.append(comment.message)
|
||||||
|
self.set_text(text)
|
||||||
|
|
||||||
|
class ThreadCommentEdit(urwid.WidgetWrap):
|
||||||
|
def __init__(self, app, thread):
|
||||||
|
super().__init__(urwid.Pile([]))
|
||||||
|
self.pile = urwid.Pile([])
|
||||||
|
self._w = urwid.AttrMap(self.pile, None, focus_map={})
|
||||||
|
self.app = app
|
||||||
|
|
||||||
|
# If we save a comment, the resulting key will be stored here
|
||||||
|
self.key = None
|
||||||
|
self.comment = mywid.MyEdit(edit_text='', multiline=True,
|
||||||
|
ring=self.app.ring)
|
||||||
|
#comment = urwid.Padding(self.comment, width=80)
|
||||||
|
self.checkbox = urwid.CheckBox('Resolved',
|
||||||
|
state=not thread.unresolved)
|
||||||
|
self.pile.contents.append((urwid.AttrMap(self.comment, 'draft-comment'),
|
||||||
|
('pack', None)))
|
||||||
|
self.pile.contents.append((urwid.AttrMap(self.checkbox,
|
||||||
|
'comment-thread-checkbox',
|
||||||
|
'focused-comment-thread-checkbox'),
|
||||||
|
('pack', None)))
|
||||||
|
#self.focus_position = 1
|
||||||
|
|
||||||
|
class ThreadBox(urwid.WidgetWrap):
|
||||||
|
focus_map={'comment-thread-button': 'focused-comment-thread-button'}
|
||||||
|
|
||||||
|
def __init__(self, change_view, change, thread):
|
||||||
|
super().__init__(urwid.Pile([]))
|
||||||
|
self.pile = urwid.Pile([])
|
||||||
|
self._w = urwid.AttrMap(self.pile, None, focus_map={})
|
||||||
|
self.change_view = change_view
|
||||||
|
self.app = change_view.app
|
||||||
|
self.change_key = change.key
|
||||||
|
self.edit = None
|
||||||
|
|
||||||
|
def x(self, button):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def deleteComment(self, comment_key):
|
||||||
|
self.app.log.debug("delete comment %s", comment_key)
|
||||||
|
with self.app.db.getSession() as session:
|
||||||
|
comment = session.getComment(comment_key)
|
||||||
|
session.delete(comment)
|
||||||
|
|
||||||
|
def saveComment(self, text):
|
||||||
|
orig_comment = self.thread.comments[0]
|
||||||
|
orig_message = orig_comment._message
|
||||||
|
in_reply_to = orig_comment.id
|
||||||
|
self.app.log.debug("save comment")
|
||||||
|
with self.app.db.getSession() as session:
|
||||||
|
account = session.getOwnAccount()
|
||||||
|
revision = session.getRevision(orig_message.revision_key)
|
||||||
|
change = session.getChange(self.change_key)
|
||||||
|
fileobj = session.getFile(orig_comment.file_key)
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
key = change.createComment(
|
||||||
|
now, revision, fileobj,
|
||||||
|
account, in_reply_to,
|
||||||
|
orig_comment.parent,
|
||||||
|
orig_comment.line, text)
|
||||||
|
|
||||||
|
"""
|
||||||
|
draft_message = revision.getPendingMessage()
|
||||||
|
self.app.log.debug("draft message 1 %s", draft_message)
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
if not draft_message:
|
||||||
|
draft_message = revision.getDraftMessage()
|
||||||
|
self.app.log.debug("draft message 2 %s", draft_message)
|
||||||
|
if not draft_message:
|
||||||
|
draft_message = revision.createMessage(None, account,
|
||||||
|
now,
|
||||||
|
'', draft=True)
|
||||||
|
self.app.log.debug("draft message 3 %s", draft_message)
|
||||||
|
for other_comment in change.getCommentsForMessage(draft_message):
|
||||||
|
self.app.log.debug("other comment %s", other_comment)
|
||||||
|
if other_comment.draft:
|
||||||
|
other_comment.created = now
|
||||||
|
draft_message.created = now
|
||||||
|
message_key = draft_message.key
|
||||||
|
fileobj = session.getFile(orig_comment.file_key)
|
||||||
|
comment = fileobj.createComment(None, account, in_reply_to,
|
||||||
|
now,
|
||||||
|
orig_comment.parent,
|
||||||
|
orig_comment.line, text, draft=True)
|
||||||
|
key = comment.key
|
||||||
|
self.app.log.debug("save comment %s %s", text, key)
|
||||||
|
return key
|
||||||
|
"""
|
||||||
|
|
||||||
|
def cleanupEdit(self):
|
||||||
|
edit = self.edit
|
||||||
|
if not edit:
|
||||||
|
return
|
||||||
|
text = edit.comment.edit_text.strip()
|
||||||
|
if text:
|
||||||
|
if edit.key:
|
||||||
|
with self.app.db.getSession() as session:
|
||||||
|
comment = session.getComment(edit.key)
|
||||||
|
comment.message = text
|
||||||
|
comment.unresolved = not edit.checkbox.get_state()
|
||||||
|
else:
|
||||||
|
edit.key = self.saveComment(text)
|
||||||
|
else:
|
||||||
|
if edit.key:
|
||||||
|
self.deleteComment(edit.key)
|
||||||
|
edit.key = None
|
||||||
|
self.closeEdit()
|
||||||
|
self.app.log.debug("XXX close edit %s", self.thread.comments)
|
||||||
|
self.change_view.refresh()
|
||||||
|
|
||||||
|
def reply(self, button):
|
||||||
|
self.openEdit()
|
||||||
|
self.pile.set_focus(len(self.pile.contents)-3)
|
||||||
|
|
||||||
|
def _addEdit(self):
|
||||||
|
row = urwid.Padding(self.edit, width=80)
|
||||||
|
self.pile.contents.insert(-2,
|
||||||
|
(row, ('pack', None)))
|
||||||
|
|
||||||
|
def openEdit(self):
|
||||||
|
if self.edit: return False
|
||||||
|
self.edit = ThreadCommentEdit(self.app, self.thread)
|
||||||
|
self._addEdit()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def closeEdit(self):
|
||||||
|
if not self.edit: return
|
||||||
|
self.edit = None
|
||||||
|
self.pile.contents.pop(-3)
|
||||||
|
|
||||||
|
def refresh(self, change, thread):
|
||||||
|
self.thread = thread
|
||||||
|
self.pile.contents = []
|
||||||
|
path = thread.path
|
||||||
|
if path == '/PATCHSET_LEVEL':
|
||||||
|
path = ''
|
||||||
|
if path == '/COMMIT_MSG':
|
||||||
|
path = 'Commit message'
|
||||||
|
location = f'Patchset {thread.patchset} {path} {thread.line}'
|
||||||
|
|
||||||
|
unresolved = thread.unresolved
|
||||||
|
if thread.has_draft:
|
||||||
|
unresolved = True
|
||||||
|
if unresolved:
|
||||||
|
style = 'comment-thread-unresolved'
|
||||||
|
else:
|
||||||
|
style = 'comment-thread-resolved'
|
||||||
|
self.pile.contents.append((urwid.Text((style, location)), ('pack', None)))
|
||||||
|
|
||||||
|
draft_comment = None
|
||||||
|
#self.listbox.body.append('thread')
|
||||||
|
listbox_index = 0
|
||||||
|
for comment in thread.comments:
|
||||||
|
message = comment._message
|
||||||
|
self.app.log.debug("comment: %s %s", message.key, comment.message)
|
||||||
|
if comment.draft:
|
||||||
|
draft_comment = comment
|
||||||
|
else:
|
||||||
|
box = ThreadCommentBox(self, change, thread, message, comment)
|
||||||
|
row = urwid.Padding(box, width=80)
|
||||||
|
self.pile.contents.append((row, ('pack', None)))
|
||||||
|
#self.message_rows[message.key] = row
|
||||||
|
|
||||||
|
buttons = [
|
||||||
|
mywid.FixedButton(('comment-thread-button', "Reply"),
|
||||||
|
on_press=self.reply),
|
||||||
|
mywid.FixedButton(('comment-thread-button', "Quote"),
|
||||||
|
on_press=self.x),
|
||||||
|
]
|
||||||
|
if unresolved:
|
||||||
|
buttons.append(
|
||||||
|
mywid.FixedButton(('comment-thread-button', "Ack"),
|
||||||
|
on_press=self.x))
|
||||||
|
buttons.append(
|
||||||
|
mywid.FixedButton(('comment-thread-button', "Done"),
|
||||||
|
on_press=self.x))
|
||||||
|
|
||||||
|
buttons = [('pack', urwid.AttrMap(b, None, focus_map=self.focus_map)) for b in buttons]
|
||||||
|
buttons = urwid.Columns(buttons + [urwid.Text('')], dividechars=2)
|
||||||
|
buttons = urwid.AttrMap(buttons, 'comment-thread-button')
|
||||||
|
|
||||||
|
self.pile.contents.append((buttons, ('pack', None)))
|
||||||
|
self.pile.contents.append((urwid.Text(''), ('pack', None)))
|
||||||
|
|
||||||
|
if draft_comment:
|
||||||
|
if not self.openEdit():
|
||||||
|
self._addEdit()
|
||||||
|
self.edit.comment.set_edit_text(draft_comment.message)
|
||||||
|
self.edit.key = draft_comment.key
|
||||||
|
self.pile.set_focus(len(self.pile.contents)-3)
|
||||||
|
else:
|
||||||
|
self.pile.set_focus(len(self.pile.contents)-2)
|
||||||
|
|
||||||
class ChangeMessageBox(mywid.HyperText):
|
class ChangeMessageBox(mywid.HyperText):
|
||||||
def __init__(self, change_view, change, message):
|
def __init__(self, change_view, change, message):
|
||||||
super(ChangeMessageBox, self).__init__(u'')
|
super(ChangeMessageBox, self).__init__(u'')
|
||||||
@ -495,19 +738,22 @@ class ChangeMessageBox(mywid.HyperText):
|
|||||||
comment_ps = revno + 1
|
comment_ps = revno + 1
|
||||||
if comment_ps == message.revision.number:
|
if comment_ps == message.revision.number:
|
||||||
comment_ps = None
|
comment_ps = None
|
||||||
inline_comments[path].append((comment_ps or 0, comment.line or 0, comment.message))
|
comment_key = (comment_ps or 0, comment.line or 0, comment.message)
|
||||||
|
inline_comments[path].append((comment_key, comment))
|
||||||
for v in inline_comments.values():
|
for v in inline_comments.values():
|
||||||
v.sort()
|
# Sort on comment_key
|
||||||
|
v.sort(key=lambda x: x[0])
|
||||||
|
|
||||||
if inline_comments:
|
if inline_comments:
|
||||||
comment_text.append(u'\n')
|
comment_text.append(u'\n')
|
||||||
for key, value in inline_comments.items():
|
for path, comment_list in inline_comments.items():
|
||||||
if key == '/PATCHSET_LEVEL':
|
if path == '/PATCHSET_LEVEL':
|
||||||
key = 'Patchset'
|
path = 'Patchset'
|
||||||
if key == '/COMMIT_MSG':
|
if path == '/COMMIT_MSG':
|
||||||
key = 'Commit message'
|
path = 'Commit message'
|
||||||
comment_text.append(('filename-inline-comment', u'%s' % key))
|
comment_text.append(('filename-inline-comment', u'%s' % path))
|
||||||
for patchset, line, comment in value:
|
for comment_key, comment in comment_list:
|
||||||
|
patchset, line, message = comment_key
|
||||||
location_str = ''
|
location_str = ''
|
||||||
if patchset:
|
if patchset:
|
||||||
location_str += "PS%i" % patchset
|
location_str += "PS%i" % patchset
|
||||||
@ -516,8 +762,9 @@ class ChangeMessageBox(mywid.HyperText):
|
|||||||
location_str += str(line)
|
location_str += str(line)
|
||||||
if location_str:
|
if location_str:
|
||||||
location_str += ": "
|
location_str += ": "
|
||||||
comment_text.append(u'\n %s%s\n' % (location_str, comment))
|
comment_text.append(u'\n %s%s\n' % (location_str, message))
|
||||||
|
comment_text.append(f'{comment.unresolved}\n')
|
||||||
|
self.app.log.debug(f'unresolved: {comment.unresolved}\n')
|
||||||
self.set_text(text+comment_text)
|
self.set_text(text+comment_text)
|
||||||
|
|
||||||
class CommitMessageBox(mywid.HyperText):
|
class CommitMessageBox(mywid.HyperText):
|
||||||
@ -597,6 +844,7 @@ class ChangeView(urwid.WidgetWrap):
|
|||||||
self.log = logging.getLogger('gertty.view.change')
|
self.log = logging.getLogger('gertty.view.change')
|
||||||
self.app = app
|
self.app = app
|
||||||
self.change_key = change_key
|
self.change_key = change_key
|
||||||
|
self.thread_rows = {}
|
||||||
self.revision_rows = {}
|
self.revision_rows = {}
|
||||||
self.message_rows = {}
|
self.message_rows = {}
|
||||||
self.last_revision_key = None
|
self.last_revision_key = None
|
||||||
@ -838,6 +1086,25 @@ class ChangeView(urwid.WidgetWrap):
|
|||||||
if len(self.listbox.body) == listbox_index:
|
if len(self.listbox.body) == listbox_index:
|
||||||
self.listbox.body.insert(listbox_index, urwid.Divider())
|
self.listbox.body.insert(listbox_index, urwid.Divider())
|
||||||
listbox_index += 1
|
listbox_index += 1
|
||||||
|
|
||||||
|
# XXX
|
||||||
|
unseen_keys = set(self.thread_rows.keys())
|
||||||
|
for thread in change.getThreads():
|
||||||
|
self.app.log.debug("thread: %s %s", thread.key, thread.unresolved)
|
||||||
|
row = self.thread_rows.get(thread.key)
|
||||||
|
if not row:
|
||||||
|
row = ThreadBox(self, change, thread)
|
||||||
|
self.listbox.body.insert(listbox_index, row)
|
||||||
|
self.thread_rows[thread.key] = row
|
||||||
|
row.refresh(change, thread)
|
||||||
|
listbox_index += 1
|
||||||
|
unseen_keys.discard(thread.key)
|
||||||
|
for key in unseen_keys:
|
||||||
|
row = self.thread_rows.get(key)
|
||||||
|
self.listbox.body.remove(row)
|
||||||
|
del self.thread_rows[key]
|
||||||
|
listbox_index -= 1
|
||||||
|
|
||||||
# Get the set of messages that should be displayed
|
# Get the set of messages that should be displayed
|
||||||
display_messages = []
|
display_messages = []
|
||||||
result_systems = {}
|
result_systems = {}
|
||||||
@ -1006,10 +1273,18 @@ class ChangeView(urwid.WidgetWrap):
|
|||||||
return self.app.toggleHeldChange(self.change_key)
|
return self.app.toggleHeldChange(self.change_key)
|
||||||
|
|
||||||
def keypress(self, size, key):
|
def keypress(self, size, key):
|
||||||
|
old_focus = self.listbox.focus
|
||||||
if not self.app.input_buffer:
|
if not self.app.input_buffer:
|
||||||
key = super(ChangeView, self).keypress(size, key)
|
key = super(ChangeView, self).keypress(size, key)
|
||||||
|
new_focus = self.listbox.focus
|
||||||
|
|
||||||
keys = self.app.input_buffer + [key]
|
keys = self.app.input_buffer + [key]
|
||||||
commands = self.app.config.keymap.getCommands(keys)
|
commands = self.app.config.keymap.getCommands(keys)
|
||||||
|
|
||||||
|
if (isinstance(old_focus, ThreadBox) and
|
||||||
|
(old_focus != new_focus or (keymap.PREV_SCREEN in commands))):
|
||||||
|
old_focus.cleanupEdit()
|
||||||
|
|
||||||
if keymap.TOGGLE_REVIEWED in commands:
|
if keymap.TOGGLE_REVIEWED in commands:
|
||||||
self.toggleReviewed()
|
self.toggleReviewed()
|
||||||
self.refresh()
|
self.refresh()
|
||||||
|
@ -100,7 +100,7 @@ class BaseDiffCommentEdit(urwid.Columns):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
class BaseDiffComment(urwid.Columns):
|
class BaseDiffComment(urwid.Columns):
|
||||||
pass
|
focus_map={'comment-thread-button': 'focused-comment-thread-button'}
|
||||||
|
|
||||||
class BaseDiffLine(urwid.Button):
|
class BaseDiffLine(urwid.Button):
|
||||||
def selectable(self):
|
def selectable(self):
|
||||||
@ -193,6 +193,7 @@ class BaseDiffView(urwid.WidgetWrap, mywid.Searchable):
|
|||||||
self.searchInit()
|
self.searchInit()
|
||||||
with self.app.db.getSession() as session:
|
with self.app.db.getSession() as session:
|
||||||
new_revision = session.getRevision(self.new_revision_key)
|
new_revision = session.getRevision(self.new_revision_key)
|
||||||
|
new_revision.change.makeThreads()
|
||||||
old_comments = []
|
old_comments = []
|
||||||
new_comments = []
|
new_comments = []
|
||||||
self.old_file_keys = {}
|
self.old_file_keys = {}
|
||||||
@ -251,12 +252,12 @@ class BaseDiffView(urwid.WidgetWrap, mywid.Searchable):
|
|||||||
key += '-' + str(comment.line)
|
key += '-' + str(comment.line)
|
||||||
key += '-' + path
|
key += '-' + path
|
||||||
comment_list = comment_lists.get(key, [])
|
comment_list = comment_lists.get(key, [])
|
||||||
if comment.draft:
|
#if comment.draft:
|
||||||
message = comment.message
|
# message = comment.message
|
||||||
else:
|
#else:
|
||||||
message = [('comment-name', comment.author.name),
|
# message = [('comment-name', comment.author.name),
|
||||||
('comment', u': '+comment.message)]
|
# ('comment', u': '+comment.message)]
|
||||||
comment_list.append((comment.key, message))
|
comment_list.append((comment.key, comment))
|
||||||
comment_lists[key] = comment_list
|
comment_lists[key] = comment_list
|
||||||
comment_filenames.add(path)
|
comment_filenames.add(path)
|
||||||
for comment in old_comments:
|
for comment in old_comments:
|
||||||
@ -271,12 +272,12 @@ class BaseDiffView(urwid.WidgetWrap, mywid.Searchable):
|
|||||||
key += '-' + str(comment.line)
|
key += '-' + str(comment.line)
|
||||||
key += '-' + path
|
key += '-' + path
|
||||||
comment_list = comment_lists.get(key, [])
|
comment_list = comment_lists.get(key, [])
|
||||||
if comment.draft:
|
#if comment.draft:
|
||||||
message = comment.message
|
# message = comment.message
|
||||||
else:
|
#else:
|
||||||
message = [('comment-name', comment.author.name),
|
# message = [('comment-name', comment.author.name),
|
||||||
('comment', u': '+comment.message)]
|
# ('comment', u': '+comment.message)]
|
||||||
comment_list.append((comment.key, message))
|
comment_list.append((comment.key, comment))
|
||||||
comment_lists[key] = comment_list
|
comment_lists[key] = comment_list
|
||||||
comment_filenames.add(path)
|
comment_filenames.add(path)
|
||||||
repo = gitrepo.get_repo(self.project_name, self.app.config)
|
repo = gitrepo.get_repo(self.project_name, self.app.config)
|
||||||
@ -502,12 +503,15 @@ class BaseDiffView(urwid.WidgetWrap, mywid.Searchable):
|
|||||||
self.cleanupEdit(old_focus)
|
self.cleanupEdit(old_focus)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def makeCommentEdit(self, edit):
|
def makeCommentEdit(self, edit, **kw):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def onSelect(self, button):
|
def onSelect(self, button):
|
||||||
|
self.createComment()
|
||||||
|
|
||||||
|
def createComment(self, **kw):
|
||||||
pos = self.listbox.focus_position
|
pos = self.listbox.focus_position
|
||||||
e = self.makeCommentEdit(self.listbox.body[pos])
|
e = self.makeCommentEdit(self.listbox.body[pos], **kw)
|
||||||
self.listbox.body.insert(pos+1, e)
|
self.listbox.body.insert(pos+1, e)
|
||||||
self.listbox.focus_position = pos+1
|
self.listbox.focus_position = pos+1
|
||||||
|
|
||||||
@ -519,7 +523,7 @@ class BaseDiffView(urwid.WidgetWrap, mywid.Searchable):
|
|||||||
comment = session.getComment(comment_key)
|
comment = session.getComment(comment_key)
|
||||||
session.delete(comment)
|
session.delete(comment)
|
||||||
|
|
||||||
def saveComment(self, context, text, new=True):
|
def saveComment(self, context, text, in_reply_to, new=True):
|
||||||
if (not new) and (not self.old_revision_num):
|
if (not new) and (not self.old_revision_num):
|
||||||
parent = True
|
parent = True
|
||||||
else:
|
else:
|
||||||
@ -527,19 +531,33 @@ class BaseDiffView(urwid.WidgetWrap, mywid.Searchable):
|
|||||||
if new:
|
if new:
|
||||||
line_num = context.new_ln
|
line_num = context.new_ln
|
||||||
file_key = context.new_file_key
|
file_key = context.new_file_key
|
||||||
|
revision_key = self.new_revision_key
|
||||||
else:
|
else:
|
||||||
line_num = context.old_ln
|
line_num = context.old_ln
|
||||||
file_key = context.old_file_key
|
file_key = context.old_file_key
|
||||||
|
revision_key = self.old_revision_key or self.new_revision_key
|
||||||
if file_key is None:
|
if file_key is None:
|
||||||
raise Exception("Comment is not associated with a file")
|
raise Exception("Comment is not associated with a file")
|
||||||
with self.app.db.getSession() as session:
|
with self.app.db.getSession() as session:
|
||||||
fileobj = session.getFile(file_key)
|
fileobj = session.getFile(file_key)
|
||||||
account = session.getOwnAccount()
|
account = session.getOwnAccount()
|
||||||
|
revision = session.getRevision(revision_key)
|
||||||
|
change = session.getChange(self.change_key)
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
self.log.debug("XXX create comment %s %s", in_reply_to, text)
|
||||||
|
key = change.createComment(
|
||||||
|
now, revision, fileobj,
|
||||||
|
account, in_reply_to,
|
||||||
|
parent,
|
||||||
|
line_num, text)
|
||||||
|
|
||||||
|
"""
|
||||||
comment = fileobj.createComment(None, account, None,
|
comment = fileobj.createComment(None, account, None,
|
||||||
datetime.datetime.utcnow(),
|
datetime.datetime.utcnow(),
|
||||||
parent,
|
parent,
|
||||||
line_num, text, draft=True)
|
line_num, text, draft=True)
|
||||||
key = comment.key
|
key = comment.key
|
||||||
|
"""
|
||||||
return key
|
return key
|
||||||
|
|
||||||
def reviewKey(self, reviewkey):
|
def reviewKey(self, reviewkey):
|
||||||
|
@ -22,13 +22,16 @@ from gertty.view.diff import BaseFileHeader, BaseFileReminder, BaseDiffView
|
|||||||
LN_COL_WIDTH = 5
|
LN_COL_WIDTH = 5
|
||||||
|
|
||||||
class SideDiffCommentEdit(BaseDiffCommentEdit):
|
class SideDiffCommentEdit(BaseDiffCommentEdit):
|
||||||
def __init__(self, app, context, old_key=None, new_key=None, old=u'', new=u''):
|
def __init__(self, app, context, old_key=None, new_key=None, old=u'', new=u'',
|
||||||
|
old_irp=None, new_irp=None):
|
||||||
super(SideDiffCommentEdit, self).__init__([])
|
super(SideDiffCommentEdit, self).__init__([])
|
||||||
self.app = app
|
self.app = app
|
||||||
self.context = context
|
self.context = context
|
||||||
# If we save a comment, the resulting key will be stored here
|
# If we save a comment, the resulting key will be stored here
|
||||||
self.old_key = old_key
|
self.old_key = old_key
|
||||||
self.new_key = new_key
|
self.new_key = new_key
|
||||||
|
self.old_irp = old_irp
|
||||||
|
self.new_irp = new_irp
|
||||||
self.old = mywid.MyEdit(edit_text=old, multiline=True, ring=app.ring)
|
self.old = mywid.MyEdit(edit_text=old, multiline=True, ring=app.ring)
|
||||||
self.new = mywid.MyEdit(edit_text=new, multiline=True, ring=app.ring)
|
self.new = mywid.MyEdit(edit_text=new, multiline=True, ring=app.ring)
|
||||||
self.contents.append((urwid.Text(u''), ('given', LN_COL_WIDTH, False)))
|
self.contents.append((urwid.Text(u''), ('given', LN_COL_WIDTH, False)))
|
||||||
@ -67,20 +70,62 @@ class SideDiffCommentEdit(BaseDiffCommentEdit):
|
|||||||
return key
|
return key
|
||||||
|
|
||||||
class SideDiffComment(BaseDiffComment):
|
class SideDiffComment(BaseDiffComment):
|
||||||
def __init__(self, context, old, new):
|
def __init__(self, view, context, old, new, old_irp, new_irp):
|
||||||
super(SideDiffComment, self).__init__([])
|
super(SideDiffComment, self).__init__([])
|
||||||
|
self.view = view
|
||||||
self.context = context
|
self.context = context
|
||||||
oldt = urwid.Text(old)
|
self.old_irp = old_irp
|
||||||
newt = urwid.Text(new)
|
self.new_irp = new_irp
|
||||||
if old:
|
|
||||||
oldt = urwid.AttrMap(oldt, 'comment')
|
oldt = self.formatText(old, old_irp, None)
|
||||||
if new:
|
newt = self.formatText(new, None, new_irp)
|
||||||
newt = urwid.AttrMap(newt, 'comment')
|
|
||||||
self.contents.append((urwid.Text(u''), ('given', LN_COL_WIDTH, False)))
|
self.contents.append((urwid.Text(u''), ('given', LN_COL_WIDTH, False)))
|
||||||
self.contents.append((oldt, ('weight', 1, False)))
|
self.contents.append((oldt, ('weight', 1, False)))
|
||||||
self.contents.append((urwid.Text(u''), ('given', LN_COL_WIDTH, False)))
|
self.contents.append((urwid.Text(u''), ('given', LN_COL_WIDTH, False)))
|
||||||
self.contents.append((newt, ('weight', 1, False)))
|
self.contents.append((newt, ('weight', 1, False)))
|
||||||
|
|
||||||
|
def reply(self, button, user_data):
|
||||||
|
old_irp, new_irp = user_data
|
||||||
|
self.view.createComment(old_irp=old_irp, new_irp=new_irp)
|
||||||
|
|
||||||
|
def x(self, button):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def formatText(self, comment, old_irp, new_irp):
|
||||||
|
if not comment:
|
||||||
|
return urwid.Text('')
|
||||||
|
if comment.draft:
|
||||||
|
message = comment.message
|
||||||
|
else:
|
||||||
|
message = [('comment-name', comment.author.name),
|
||||||
|
('comment', u': '+comment.message)]
|
||||||
|
text = urwid.Text(message)
|
||||||
|
ret = urwid.AttrMap(text, 'comment')
|
||||||
|
if comment._thread.comments[-1] is comment:
|
||||||
|
# Last comment in a thread
|
||||||
|
|
||||||
|
buttons = [
|
||||||
|
mywid.FixedButton(('comment-thread-button', "Reply"),
|
||||||
|
on_press=self.reply, user_data=(old_irp, new_irp)),
|
||||||
|
mywid.FixedButton(('comment-thread-button', "Quote"),
|
||||||
|
on_press=self.x),
|
||||||
|
]
|
||||||
|
if comment._thread.unresolved:
|
||||||
|
buttons.append(
|
||||||
|
mywid.FixedButton(('comment-thread-button', "Ack"),
|
||||||
|
on_press=self.x))
|
||||||
|
buttons.append(
|
||||||
|
mywid.FixedButton(('comment-thread-button', "Done"),
|
||||||
|
on_press=self.x))
|
||||||
|
|
||||||
|
buttons = [('pack', urwid.AttrMap(b, None, focus_map=self.focus_map)) for b in buttons]
|
||||||
|
buttons = urwid.Columns(buttons + [urwid.Text('')], dividechars=2)
|
||||||
|
buttons = urwid.AttrMap(buttons, 'comment-thread-button')
|
||||||
|
|
||||||
|
pile = urwid.Pile([ret, buttons])
|
||||||
|
ret = pile
|
||||||
|
return ret
|
||||||
|
|
||||||
class SideDiffLine(BaseDiffLine):
|
class SideDiffLine(BaseDiffLine):
|
||||||
def __init__(self, app, context, old, new, callback=None):
|
def __init__(self, app, context, old, new, callback=None):
|
||||||
super(SideDiffLine, self).__init__('', on_press=callback)
|
super(SideDiffLine, self).__init__('', on_press=callback)
|
||||||
@ -152,14 +197,22 @@ class SideDiffView(BaseDiffView):
|
|||||||
old_list = comment_lists.pop(key, [])
|
old_list = comment_lists.pop(key, [])
|
||||||
key = 'new-%s-%s' % (new[0], diff.newname)
|
key = 'new-%s-%s' % (new[0], diff.newname)
|
||||||
new_list = comment_lists.pop(key, [])
|
new_list = comment_lists.pop(key, [])
|
||||||
|
old_irp = new_irp = None
|
||||||
while old_list or new_list:
|
while old_list or new_list:
|
||||||
old_comment_key = new_comment_key = None
|
old_comment_key = new_comment_key = None
|
||||||
old_comment = new_comment = u''
|
old_comment = new_comment = u''
|
||||||
if old_list:
|
if old_list:
|
||||||
(old_comment_key, old_comment) = old_list.pop(0)
|
(old_comment_key, old_comment) = old_list.pop(0)
|
||||||
|
if old_comment._thread.comments[0] is old_comment:
|
||||||
|
# First comment in thread
|
||||||
|
old_irp = old_comment.id
|
||||||
if new_list:
|
if new_list:
|
||||||
(new_comment_key, new_comment) = new_list.pop(0)
|
(new_comment_key, new_comment) = new_list.pop(0)
|
||||||
lines.append(SideDiffComment(context, old_comment, new_comment))
|
if new_comment._thread.comments[0] is new_comment:
|
||||||
|
# First comment in thread
|
||||||
|
new_irp = new_comment.id
|
||||||
|
lines.append(SideDiffComment(self, context, old_comment, new_comment,
|
||||||
|
old_irp, new_irp))
|
||||||
# see if there are any draft comments for this line
|
# see if there are any draft comments for this line
|
||||||
key = 'olddraft-%s-%s' % (old[0], diff.oldname)
|
key = 'olddraft-%s-%s' % (old[0], diff.oldname)
|
||||||
old_list = comment_lists.pop(key, [])
|
old_list = comment_lists.pop(key, [])
|
||||||
@ -168,14 +221,20 @@ class SideDiffView(BaseDiffView):
|
|||||||
while old_list or new_list:
|
while old_list or new_list:
|
||||||
old_comment_key = new_comment_key = None
|
old_comment_key = new_comment_key = None
|
||||||
old_comment = new_comment = u''
|
old_comment = new_comment = u''
|
||||||
|
old_irp = new_irp = None
|
||||||
if old_list:
|
if old_list:
|
||||||
(old_comment_key, old_comment) = old_list.pop(0)
|
(old_comment_key, old_comment) = old_list.pop(0)
|
||||||
|
old_irp = old_comment.in_reply_to
|
||||||
|
old_comment = old_comment.message
|
||||||
if new_list:
|
if new_list:
|
||||||
(new_comment_key, new_comment) = new_list.pop(0)
|
(new_comment_key, new_comment) = new_list.pop(0)
|
||||||
|
new_irp = new_comment.in_reply_to
|
||||||
|
new_comment = new_comment.message
|
||||||
lines.append(SideDiffCommentEdit(self.app, context,
|
lines.append(SideDiffCommentEdit(self.app, context,
|
||||||
old_comment_key,
|
old_comment_key,
|
||||||
new_comment_key,
|
new_comment_key,
|
||||||
old_comment, new_comment))
|
old_comment, new_comment,
|
||||||
|
old_irp, new_irp))
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
def makeFileReminder(self):
|
def makeFileReminder(self):
|
||||||
@ -197,8 +256,12 @@ class SideDiffView(BaseDiffView):
|
|||||||
old_comment = new_comment = u''
|
old_comment = new_comment = u''
|
||||||
if old_list:
|
if old_list:
|
||||||
(old_comment_key, old_comment) = old_list.pop(0)
|
(old_comment_key, old_comment) = old_list.pop(0)
|
||||||
|
if not old_list:
|
||||||
|
pass #XXX last comment
|
||||||
if new_list:
|
if new_list:
|
||||||
(new_comment_key, new_comment) = new_list.pop(0)
|
(new_comment_key, new_comment) = new_list.pop(0)
|
||||||
|
if not new_list:
|
||||||
|
pass #XXX last comment
|
||||||
lines.append(SideDiffComment(context, old_comment, new_comment))
|
lines.append(SideDiffComment(context, old_comment, new_comment))
|
||||||
# see if there are any draft comments for this file
|
# see if there are any draft comments for this file
|
||||||
key = 'olddraft-None-%s' % (diff.oldname,)
|
key = 'olddraft-None-%s' % (diff.oldname,)
|
||||||
@ -208,18 +271,24 @@ class SideDiffView(BaseDiffView):
|
|||||||
while old_list or new_list:
|
while old_list or new_list:
|
||||||
old_comment_key = new_comment_key = None
|
old_comment_key = new_comment_key = None
|
||||||
old_comment = new_comment = u''
|
old_comment = new_comment = u''
|
||||||
|
old_irp = new_irp = None
|
||||||
if old_list:
|
if old_list:
|
||||||
(old_comment_key, old_comment) = old_list.pop(0)
|
(old_comment_key, old_comment) = old_list.pop(0)
|
||||||
|
old_irp = old_comment.in_reply_to
|
||||||
|
old_comment = old_comment.message
|
||||||
if new_list:
|
if new_list:
|
||||||
(new_comment_key, new_comment) = new_list.pop(0)
|
(new_comment_key, new_comment) = new_list.pop(0)
|
||||||
|
new_irp = new_comment.in_reply_to
|
||||||
|
new_comment = new_comment.message
|
||||||
lines.append(SideDiffCommentEdit(self.app, context,
|
lines.append(SideDiffCommentEdit(self.app, context,
|
||||||
old_comment_key,
|
old_comment_key,
|
||||||
new_comment_key,
|
new_comment_key,
|
||||||
old_comment, new_comment))
|
old_comment, new_comment,
|
||||||
|
old_irp, new_irp))
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
def makeCommentEdit(self, edit):
|
def makeCommentEdit(self, edit, **kw):
|
||||||
return SideDiffCommentEdit(self.app, edit.context)
|
return SideDiffCommentEdit(self.app, edit.context, **kw)
|
||||||
|
|
||||||
def cleanupEdit(self, edit):
|
def cleanupEdit(self, edit):
|
||||||
if edit.old_key:
|
if edit.old_key:
|
||||||
@ -233,9 +302,9 @@ class SideDiffView(BaseDiffView):
|
|||||||
if old or new:
|
if old or new:
|
||||||
if old:
|
if old:
|
||||||
edit.old_key = self.saveComment(
|
edit.old_key = self.saveComment(
|
||||||
edit.context, old, new=False)
|
edit.context, old, edit.old_irp, new=False)
|
||||||
if new:
|
if new:
|
||||||
edit.new_key = self.saveComment(
|
edit.new_key = self.saveComment(
|
||||||
edit.context, new, new=True)
|
edit.context, new, edit.new_irp, new=True)
|
||||||
else:
|
else:
|
||||||
self.listbox.body.remove(edit)
|
self.listbox.body.remove(edit)
|
||||||
|
@ -23,12 +23,13 @@ from gertty.view.diff import BaseFileHeader, BaseFileReminder, BaseDiffView
|
|||||||
LN_COL_WIDTH = 5
|
LN_COL_WIDTH = 5
|
||||||
|
|
||||||
class UnifiedDiffCommentEdit(BaseDiffCommentEdit):
|
class UnifiedDiffCommentEdit(BaseDiffCommentEdit):
|
||||||
def __init__(self, app, context, oldnew, key=None, comment=u''):
|
def __init__(self, app, context, oldnew, key=None, comment=u'', irp=None):
|
||||||
super(UnifiedDiffCommentEdit, self).__init__([])
|
super(UnifiedDiffCommentEdit, self).__init__([])
|
||||||
self.context = context
|
self.context = context
|
||||||
self.oldnew = oldnew
|
self.oldnew = oldnew
|
||||||
# If we save a comment, the resulting key will be stored here
|
# If we save a comment, the resulting key will be stored here
|
||||||
self.key = key
|
self.key = key
|
||||||
|
self.irp = irp
|
||||||
self.comment = mywid.MyEdit(edit_text=comment, multiline=True,
|
self.comment = mywid.MyEdit(edit_text=comment, multiline=True,
|
||||||
ring=app.ring)
|
ring=app.ring)
|
||||||
self.contents.append((urwid.Text(u''), ('given', 8, False)))
|
self.contents.append((urwid.Text(u''), ('given', 8, False)))
|
||||||
@ -37,10 +38,11 @@ class UnifiedDiffCommentEdit(BaseDiffCommentEdit):
|
|||||||
self.focus_position = 1
|
self.focus_position = 1
|
||||||
|
|
||||||
class UnifiedDiffComment(BaseDiffComment):
|
class UnifiedDiffComment(BaseDiffComment):
|
||||||
def __init__(self, context, oldnew, comment):
|
def __init__(self, context, oldnew, comment, irp):
|
||||||
super(UnifiedDiffComment, self).__init__([])
|
super(UnifiedDiffComment, self).__init__([])
|
||||||
self.context = context
|
self.context = context
|
||||||
text = urwid.AttrMap(urwid.Text(comment), 'comment')
|
self.irp = irp
|
||||||
|
text = urwid.AttrMap(urwid.Text(comment.message), 'comment')
|
||||||
self.contents.append((urwid.Text(u''), ('given', 8, False)))
|
self.contents.append((urwid.Text(u''), ('given', 8, False)))
|
||||||
self.contents.append((text, ('weight', 1, False)))
|
self.contents.append((text, ('weight', 1, False)))
|
||||||
|
|
||||||
@ -140,19 +142,21 @@ class UnifiedDiffView(BaseDiffView):
|
|||||||
# see if there are any comments for this line
|
# see if there are any comments for this line
|
||||||
key = 'old-%s-%s' % (old[0], diff.oldname)
|
key = 'old-%s-%s' % (old[0], diff.oldname)
|
||||||
old_list = comment_lists.pop(key, [])
|
old_list = comment_lists.pop(key, [])
|
||||||
|
# TODO: add reply buttons
|
||||||
|
old_irp = None
|
||||||
while old_list:
|
while old_list:
|
||||||
(old_comment_key, old_comment) = old_list.pop(0)
|
(old_comment_key, old_comment) = old_list.pop(0)
|
||||||
old_cache.append(UnifiedDiffComment(context, gitrepo.OLD, old_comment))
|
old_cache.append(UnifiedDiffComment(context, gitrepo.OLD, old_comment, old_irp))
|
||||||
# see if there are any draft comments for this line
|
# see if there are any draft comments for this line
|
||||||
key = 'olddraft-%s-%s' % (old[0], diff.oldname)
|
key = 'olddraft-%s-%s' % (old[0], diff.oldname)
|
||||||
old_list = comment_lists.pop(key, [])
|
old_list = comment_lists.pop(key, [])
|
||||||
while old_list:
|
while old_list:
|
||||||
(old_comment_key, old_comment) = old_list.pop(0)
|
(old_comment_key, old_comment) = old_list.pop(0)
|
||||||
old_cache.append(UnifiedDiffCommentEdit(self.app,
|
old_cache.append(UnifiedDiffCommentEdit(self.app,
|
||||||
context,
|
context,
|
||||||
gitrepo.OLD,
|
gitrepo.OLD,
|
||||||
old_comment_key,
|
old_comment_key,
|
||||||
old_comment))
|
old_comment.message, old_irp))
|
||||||
# new line
|
# new line
|
||||||
if context.new_ln is not None and new[1] != ' ':
|
if context.new_ln is not None and new[1] != ' ':
|
||||||
if old_cache:
|
if old_cache:
|
||||||
@ -164,12 +168,14 @@ class UnifiedDiffView(BaseDiffView):
|
|||||||
# see if there are any comments for this line
|
# see if there are any comments for this line
|
||||||
key = 'new-%s-%s' % (new[0], diff.newname)
|
key = 'new-%s-%s' % (new[0], diff.newname)
|
||||||
new_list = comment_lists.pop(key, [])
|
new_list = comment_lists.pop(key, [])
|
||||||
|
# TODO: add reply buttons
|
||||||
|
new_irp = None
|
||||||
while new_list:
|
while new_list:
|
||||||
(new_comment_key, new_comment) = new_list.pop(0)
|
(new_comment_key, new_comment) = new_list.pop(0)
|
||||||
if old_cache:
|
if old_cache:
|
||||||
new_cache.append(UnifiedDiffComment(context, gitrepo.NEW, new_comment))
|
new_cache.append(UnifiedDiffComment(context, gitrepo.NEW, new_comment, new_irp))
|
||||||
else:
|
else:
|
||||||
lines.append(UnifiedDiffComment(context, gitrepo.NEW, new_comment))
|
lines.append(UnifiedDiffComment(context, gitrepo.NEW, new_comment, new_irp))
|
||||||
# see if there are any draft comments for this line
|
# see if there are any draft comments for this line
|
||||||
key = 'newdraft-%s-%s' % (new[0], diff.newname)
|
key = 'newdraft-%s-%s' % (new[0], diff.newname)
|
||||||
new_list = comment_lists.pop(key, [])
|
new_list = comment_lists.pop(key, [])
|
||||||
@ -180,13 +186,13 @@ class UnifiedDiffView(BaseDiffView):
|
|||||||
context,
|
context,
|
||||||
gitrepo.NEW,
|
gitrepo.NEW,
|
||||||
new_comment_key,
|
new_comment_key,
|
||||||
new_comment))
|
new_comment.message, new_irp))
|
||||||
else:
|
else:
|
||||||
lines.append(UnifiedDiffCommentEdit(self.app,
|
lines.append(UnifiedDiffCommentEdit(self.app,
|
||||||
context,
|
context,
|
||||||
gitrepo.NEW,
|
gitrepo.NEW,
|
||||||
new_comment_key,
|
new_comment_key,
|
||||||
new_comment))
|
new_comment.message, new_irp))
|
||||||
else:
|
else:
|
||||||
if old_cache:
|
if old_cache:
|
||||||
lines.extend(old_cache)
|
lines.extend(old_cache)
|
||||||
@ -208,17 +214,19 @@ class UnifiedDiffView(BaseDiffView):
|
|||||||
old_list = comment_lists.pop(key, [])
|
old_list = comment_lists.pop(key, [])
|
||||||
while old_list:
|
while old_list:
|
||||||
(old_comment_key, old_comment) = old_list.pop(0)
|
(old_comment_key, old_comment) = old_list.pop(0)
|
||||||
lines.append(UnifiedDiffComment(context, gitrepo.OLD, old_comment))
|
lines.append(UnifiedDiffComment(context, gitrepo.OLD, old_comment, old_irp))
|
||||||
# see if there are any draft comments for this file
|
# see if there are any draft comments for this file
|
||||||
key = 'olddraft-None-%s' % (diff.oldname,)
|
key = 'olddraft-None-%s' % (diff.oldname,)
|
||||||
old_list = comment_lists.pop(key, [])
|
old_list = comment_lists.pop(key, [])
|
||||||
|
# TODO: add reply buttons
|
||||||
|
old_irp = None
|
||||||
while old_list:
|
while old_list:
|
||||||
(old_comment_key, old_comment) = old_list.pop(0)
|
(old_comment_key, old_comment) = old_list.pop(0)
|
||||||
lines.append(UnifiedDiffCommentEdit(self.app,
|
lines.append(UnifiedDiffCommentEdit(self.app,
|
||||||
context,
|
context,
|
||||||
gitrepo.OLD,
|
gitrepo.OLD,
|
||||||
old_comment_key,
|
old_comment_key,
|
||||||
old_comment))
|
old_comment, old_irp))
|
||||||
# new line
|
# new line
|
||||||
lines.append(UnifiedFileHeader(self.app, context, gitrepo.NEW,
|
lines.append(UnifiedFileHeader(self.app, context, gitrepo.NEW,
|
||||||
diff.oldname, diff.newname,
|
diff.oldname, diff.newname,
|
||||||
@ -227,9 +235,11 @@ class UnifiedDiffView(BaseDiffView):
|
|||||||
# see if there are any comments for this file
|
# see if there are any comments for this file
|
||||||
key = 'new-None-%s' % (diff.newname,)
|
key = 'new-None-%s' % (diff.newname,)
|
||||||
new_list = comment_lists.pop(key, [])
|
new_list = comment_lists.pop(key, [])
|
||||||
|
# TODO: add reply buttons
|
||||||
|
new_irp = None
|
||||||
while new_list:
|
while new_list:
|
||||||
(new_comment_key, new_comment) = new_list.pop(0)
|
(new_comment_key, new_comment) = new_list.pop(0)
|
||||||
lines.append(UnifiedDiffComment(context, gitrepo.NEW, new_comment))
|
lines.append(UnifiedDiffComment(context, gitrepo.NEW, new_comment, new_irp))
|
||||||
# see if there are any draft comments for this file
|
# see if there are any draft comments for this file
|
||||||
key = 'newdraft-None-%s' % (diff.newname,)
|
key = 'newdraft-None-%s' % (diff.newname,)
|
||||||
new_list = comment_lists.pop(key, [])
|
new_list = comment_lists.pop(key, [])
|
||||||
@ -239,13 +249,13 @@ class UnifiedDiffView(BaseDiffView):
|
|||||||
context,
|
context,
|
||||||
gitrepo.NEW,
|
gitrepo.NEW,
|
||||||
new_comment_key,
|
new_comment_key,
|
||||||
new_comment))
|
new_comment, new_irp))
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
def makeCommentEdit(self, edit):
|
def makeCommentEdit(self, edit, **kw):
|
||||||
return UnifiedDiffCommentEdit(self.app,
|
return UnifiedDiffCommentEdit(self.app,
|
||||||
edit.context,
|
edit.context,
|
||||||
edit.oldnew)
|
edit.oldnew, **kw)
|
||||||
|
|
||||||
def cleanupEdit(self, edit):
|
def cleanupEdit(self, edit):
|
||||||
if edit.key:
|
if edit.key:
|
||||||
@ -257,6 +267,6 @@ class UnifiedDiffView(BaseDiffView):
|
|||||||
if edit.oldnew == gitrepo.NEW:
|
if edit.oldnew == gitrepo.NEW:
|
||||||
new = True
|
new = True
|
||||||
edit.key = self.saveComment(
|
edit.key = self.saveComment(
|
||||||
edit.context, comment, new=new)
|
edit.context, comment, edit.irp, new=new)
|
||||||
else:
|
else:
|
||||||
self.listbox.body.remove(edit)
|
self.listbox.body.remove(edit)
|
||||||
|
Loading…
Reference in New Issue
Block a user