Switch to side-by-side view

--- a/ForgeBlog/forgeblog/command/rssfeeds.py
+++ b/ForgeBlog/forgeblog/command/rssfeeds.py
@@ -56,27 +56,32 @@
             self.result_doc = u"%s</%s>" % (self.result_doc, tag)
 
     def handle_data(self, data):
-        if len(data.split()) == 0:
-            self.result_doc = u"%s%s" % (self.result_doc, data)
-            return
-
-        res_data = ""
-        for line in data.split('\n'):
-            if self.custom_tag_opened:
-                res_data = u"%s%s" % (res_data, self.CUSTTAG_CLOSE)
+        res_data = ''
+
+        for line in data.splitlines(True):
+            # pre-emptive special case
+            if not line or line.isspace():
+                # don't wrap all whitespace lines
+                res_data += line
+                continue
+
+            # open custom tag
+            if not self.custom_tag_opened:
+                res_data += self.CUSTTAG_OPEN
+                self.custom_tag_opened = True
+            # else: cust tag might be open already from previous incomplete data block
+
+            # data
+            res_data += line.rstrip('\r\n')  # strip EOL (add close tag before)
+
+            # close custom tag
+            if line.endswith(('\r','\n')):
+                res_data += self.CUSTTAG_CLOSE + '\n'
                 self.custom_tag_opened = False
-
-            if len(line.split()) > 0:
-                res_data = u"%s\n%s%s" % (res_data, self.CUSTTAG_OPEN, line)
-                self.custom_tag_opened = True
-            else:
-                res_data = u"%s\n" % res_data
-
-        if data[-1:] == "\n" and self.custom_tag_opened:
-            res_data = u"%s%s" % (res_data, self.CUSTTAG_CLOSE)
-            self.custom_tag_opened = False
-
-        self.result_doc = u"%s%s" % (self.result_doc, res_data)
+            # else: no EOL could mean we're dealing with incomplete data block;
+                # leave it open for next handle_data, handle_starttag, or handle_endtag to clean up
+
+        self.result_doc += res_data
 
     def handle_comment(self, data):
         if self.custom_tag_opened:
@@ -116,7 +121,7 @@
 
 class RssFeedsCommand(base.BlogCommand):
     summary = 'Rss feed client'
-    parser = base.Command.standard_parser(verbose=True)
+    parser = base.BlogCommand.standard_parser(verbose=True)
     parser.add_option('-a', '--appid', dest='appid', default='',
                       help='application id')
     parser.add_option('-u', '--username', dest='username', default='root',
@@ -160,7 +165,7 @@
         allura_base.log.info("Get feed: %s" % feed_url)
         f = feedparser.parse(feed_url)
         if f.bozo:
-            base.log.exception("%s: %s" % (feed_url, f.bozo_exception))
+            allura_base.log.exception("%s: %s" % (feed_url, f.bozo_exception))
             return
         for e in f.entries:
             title = e.title
@@ -170,15 +175,10 @@
                     if ct.type != 'text/html':
                         content += '[plain]%s[/plain]' % ct.value
                     else:
-                        if False:
-                            # FIXME: disabled until https://sourceforge.net/p/allura/tickets/4345
-                            # because the bad formatting from [plain] is worse than bad formatting from unintentional markdown syntax
-                            parser = MDHTMLParser()
-                            parser.feed(ct.value)
-                            parser.close() # must be before using the result_doc
-                            markdown_content = html2text.html2text(parser.result_doc, baseurl=e.link)
-                        else:
-                            markdown_content = html2text.html2text(ct.value, baseurl=e.link)
+                        parser = MDHTMLParser()
+                        parser.feed(ct.value)
+                        parser.close() # must be before using the result_doc
+                        markdown_content = html2text.html2text(parser.result_doc, baseurl=e.link)
 
                         content += markdown_content
             else: