Added reply handling to comments
authorAaron Bentley <abentley@panoramicfeedback.com>
Mon, 3 Apr 2006 17:42:14 +0000 (13:42 -0400)
committerAaron Bentley <abentley@panoramicfeedback.com>
Mon, 3 Apr 2006 17:42:14 +0000 (13:42 -0400)
becommands/comment.py
becommands/show.py
libbe/bugdir.py
libbe/cmdutil.py

index 37fd37d63ee8b70512040de069a48eda2b18c488..4f0bf3b8ba67ecec1cc18e088001e9f6989dd365 100644 (file)
@@ -46,7 +46,7 @@ def execute(args):
     options, args = get_parser().parse_args(args)
     if len(args) < 1:
         raise cmdutil.UsageError()
-    bug = cmdutil.get_bug(args[0])
+    bug, parent_comment = cmdutil.get_bug_and_comment(args[0])
     if len(args) == 1:
         try:
             body = utility.editor_string()
@@ -61,15 +61,21 @@ def execute(args):
             body+='\n'
 
     comment = bugdir.new_comment(bug, body)
+    if parent_comment is not None:
+        comment.in_reply_to = parent_comment.uuid
     comment.save()
 
 
 def get_parser():
-    parser = cmdutil.CmdOptionParser("be comment BUG-ID COMMENT")
+    parser = cmdutil.CmdOptionParser("be comment ID COMMENT")
     return parser
 
 longhelp="""
-Add a comment to a bug.
+To add a comment to a bug, use the bug ID as the argument.  To reply to another
+comment, specify the comment name (as shown in "be show" output).
+
+$EDITOR is used to launch an editor.  If unspecified, no comment will be
+created.)
 """
 
 def help():
index 9e6058698b21b683f4362716c27ffbc48ee68d65..db3bb90e7bb1b86740d15c54e2baa4e0636b9ccc 100644 (file)
@@ -30,8 +30,11 @@ def execute(args):
         time_str = "%s (%s)" % (utility.handy_time(bug.time), 
                                 utility.time_to_str(bug.time))
     print "Created: %s" % time_str
-    for comment in bug.list_comments():
-        print "--------- Comment ---------"
-        print "From: %s" % comment.From
-        print "Date: %s\n" % utility.time_to_str(comment.date)
-        print comment.body.rstrip('\n')
+    unique_name = cmdutil.unique_name(bug, bug_dir.list())
+    comments = []
+    name_map = {}
+    for c_name, comment in cmdutil.iter_comment_name(bug, unique_name):
+        name_map[comment.uuid] = c_name
+        comments.append(comment)
+    threaded = bugdir.thread_comments(comments)
+    cmdutil.print_threaded_comments(threaded, name_map)
index b78ec069f37362bd0bc5f3baf9f3f974fbb38216..fafd1ac5bddf416b394b85adb795d5bb250e0f10 100644 (file)
@@ -370,7 +370,28 @@ class Comment(object):
         if name is None:
             return my_dir
         return os.path.join(my_dir, name)
-        
+
+
+def thread_comments(comments):
+    child_map = {}
+    top_comments = []
+    for comment in comments:
+        child_map[comment.uuid] = []
+    for comment in comments:
+        if comment.in_reply_to is None or comment.in_reply_to not in child_map:
+            top_comments.append(comment)
+            continue
+        child_map[comment.in_reply_to].append(comment)
+
+    def recurse_children(comment):
+        child_list = []
+        for child in child_map[comment.uuid]:
+            child_list.append(recurse_children(child))
+        return (comment, child_list)
+    print top_comments
+    return [recurse_children(c) for c in top_comments]
+
+
 def pyname_to_header(name):
     return name.capitalize().replace('_', '-')
     
index 2f24490cdf5ee1a347a8d1c31a58d065ad990764..3c5baae177bcfad47cde6da7b8dee1fd0703c1b5 100644 (file)
@@ -19,6 +19,8 @@ import plugin
 import locale
 import os
 import optparse
+from textwrap import TextWrapper
+from StringIO import StringIO
 import utility
 
 def unique_name(bug, bugs):
@@ -118,6 +120,34 @@ def raise_get_help(option, opt, value, parser):
     raise GetHelp
 
 
+def iter_comment_name(bug, unique_name):
+    """Iterate through id, comment pairs, in date order.
+    (This is a user-friendly id, not the comment uuid)
+    """
+    def key(comment):
+        return comment.date
+    for num, comment in enumerate(sorted(bug.list_comments(), key=key)):
+        yield ("%s:%d" % (unique_name, num+1), comment)
+
+
+def comment_from_name(bug, unique_name, name):
+    """Use a comment name to look up a comment"""
+    for cur_name, comment in iter_comment_name(bug, unique_name):
+        if name == cur_name:
+            return comment
+    raise KeyError(name)
+
+
+def get_bug_and_comment(identifier, bug_dir=None):
+    ids = identifier.split(':')
+    bug = get_bug(ids[0], bug_dir)
+    if len(ids) == 2:
+        comment = comment_from_name(bug, ids[0], identifier)
+    else:
+        comment = None
+    return bug, comment
+
+        
 class CmdOptionParser(optparse.OptionParser):
     def __init__(self, usage):
         optparse.OptionParser.__init__(self, usage)
@@ -148,6 +178,24 @@ def underlined(instring):
     return "%s\n%s" % (instring, "="*len(instring))
 
 
+def print_threaded_comments(comments, name_map, indent=""):
+    """Print a threaded display of comments"""
+    tw = TextWrapper(initial_indent = indent, subsequent_indent = indent, 
+                     width=80)
+    for comment, children in comments:
+        s = StringIO()
+        print >> s, "--------- Comment ---------"
+        print >> s, "Name: %s" % name_map[comment.uuid]
+        print >> s, "From: %s" % comment.From
+        print >> s, "Date: %s\n" % utility.time_to_str(comment.date)
+        print >> s, comment.body.rstrip('\n')
+
+        s.seek(0)
+        for line in s:
+            print tw.fill(line).rstrip('\n')
+        print_threaded_comments(children, name_map, indent=indent+"    ")
+
+
 def bug_tree(dir=None):
     """Retrieve the bug tree specified by the user.  If no directory is
     specified, the current working directory is used.