`be html` links (<a href="...) #-delimited references in text/* bodies.
authorW. Trevor King <wking@drexel.edu>
Wed, 27 Jan 2010 17:06:53 +0000 (12:06 -0500)
committerW. Trevor King <wking@drexel.edu>
Wed, 27 Jan 2010 17:06:53 +0000 (12:06 -0500)
NEWS
libbe/command/html.py
libbe/util/id.py

diff --git a/NEWS b/NEWS
index e8f502fc8f37bd3d7a130fb3cbfdfea7384ca925..46eeb370383a1a599fd3c456277991a5ba1c9af5 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+January 27, 2010
+ * `be html` links (<a href="...) #-delimited references in text/*
+   comment bodies.
+
 January 25, 2010
  * Added --ssl to `be serve` using cherrypy.wsgiserver.
 
index 0b4cf89faea31cdcba353fd029e025acc963e532..bac310fb04357d3feb7e3d87064407c4ed4e466f 100644 (file)
@@ -28,6 +28,7 @@ import libbe
 import libbe.command
 import libbe.command.util
 import libbe.util.encoding
+import libbe.util.id
 
 
 class HTML (libbe.command.Command):
@@ -222,16 +223,19 @@ class HTMLGen (object):
             if depth == 0:
                 comment_entries.append('<div class="comment root">')
             else:
-                comment_entries.append('<div class="comment">')
+                comment_entries.append(
+                    '<div class="comment" id="%s">' % comment.uuid)
             template_info = {'shortname': comment.id.user()}
             for attr in ['uuid', 'author', 'date', 'body']:
                 value = getattr(comment, attr)
                 if attr == 'body':
+                    link_long_ids = False
                     save_body = False
                     if comment.content_type == 'text/html':
-                        pass # no need to escape html...
+                        link_long_ids = True
                     elif comment.content_type.startswith('text/'):
                         value = '<pre>\n'+self._escape(value)+'\n</pre>'
+                        link_long_ids = True
                     elif comment.content_type.startswith('image/'):
                         save_body = True
                         value = '<img src="./%s/%s" />' \
@@ -240,6 +244,8 @@ class HTMLGen (object):
                         save_body = True
                         value = '<a href="./%s/%s">Link to %s file</a>.' \
                             % (bug.uuid, comment.uuid, comment.content_type)
+                    if link_long_ids == True:
+                        value = self._long_to_linked_user(value)
                     if save_body == True:
                         per_bug_dir = os.path.join(self.out_dir_bugs, bug.uuid)
                         if not os.path.exists(per_bug_dir):
@@ -249,9 +255,7 @@ class HTMLGen (object):
                             '<Files %s>\n  ForceType %s\n</Files>' \
                                 % (comment.uuid, comment.content_type),
                             [per_bug_dir, '.htaccess'], mode='a')
-                        self._write_file( # TODO: long_to_linked_user()
-                            libbe.util.id.long_to_short_text(
-                                [self.bd], comment.body),
+                        self._write_file(comment.body,
                             [per_bug_dir, comment.uuid], mode='wb')
                 else:
                     value = self._escape(value)
@@ -262,6 +266,31 @@ class HTMLGen (object):
             comment_entries.append('</div>\n') # close every remaining <div class='comment...
         return '\n'.join(comment_entries)
 
+    def _long_to_linked_user(self, text):
+        replacer = libbe.util.id.IDreplacer(
+            [self.bd], self._long_to_linked_user_replacer, wrap=False)
+        return re.sub(
+            libbe.util.id.REGEXP, replacer, text)
+
+    def _long_to_linked_user_replacer(self, bugdirs, long_id):
+        try:
+            p = libbe.util.id.parse_user(bugdirs[0], long_id)
+            short_id = libbe.util.id.long_to_short_user(bugdirs, long_id)
+        except (libbe.util.id.MultipleIDMatches,
+                libbe.util.id.NoIDMatches,
+                libbe.util.id.InvalidIDStructure), e:
+            return long_id
+        if p['type'] == 'bugdir':
+            return long_id
+        elif p['type'] == 'bug':
+            return '<a href="./%s.html">%s</a>' \
+                % (p['bug'], short_id)
+        elif p['type'] == 'comment':
+            return '<a href="./%s.html#%s">%s</a>' \
+                % (p['bug'], p['comment'], short_id)
+        raise Exception('Invalid id type %s for "%s"'
+                        % (p['type'], long_id))
+
     def _write_index_file(self, bugs, title, index_header, bug_type='active'):
         if self.verbose:
             print >> self.stdout, 'Writing %s index file for %d bugs' % (bug_type, len(bugs))
index 4537c863af2d939f09817e598fd27a570340af35..3c6c9576b0e91440b5fb4c8dfa2cdc55c3664bba 100644 (file)
@@ -191,10 +191,14 @@ class ID (object):
     Related tools:
       * get uuids back out of the user ids:
         parse_user()
-      * scan text for user ids & convert to long user ids:
+      * convert a single short user id to a long user id:
         short_to_long_user()
-      * scan text for long user ids & convert to short user ids:
+      * convert a single long user id to a short user id:
         long_to_short_user()
+      * scan text for user ids & convert to long user ids:
+        short_to_long_text()
+      * scan text for long user ids & convert to short user ids:
+        long_to_short_text()
 
     Supported types: 'bugdir', 'bug', 'comment'
     """
@@ -277,16 +281,20 @@ def short_to_long_user(bugdirs, id):
 REGEXP = '#([-a-f0-9]*)(/[-a-g0-9]*)?(/[-a-g0-9]*)?#'
 
 class IDreplacer (object):
-    def __init__(self, bugdirs, replace_fn):
+    def __init__(self, bugdirs, replace_fn, wrap=True):
         self.bugdirs = bugdirs
         self.replace_fn = replace_fn
+        self.wrap = wrap
     def __call__(self, match):
         ids = []
         for m in match.groups():
             if m == None:
                 m = ''
             ids.append(m)
-        return '#' + self.replace_fn(self.bugdirs, ''.join(ids)) + '#'
+        replacement = self.replace_fn(self.bugdirs, ''.join(ids))
+        if self.wrap == True:
+            return '#%s#' % replacement
+        return replacement
 
 def short_to_long_text(bugdirs, text):
     return re.sub(REGEXP, IDreplacer(bugdirs, short_to_long_user), text)