From 82e868a0cc709504804c467523bff9c8a896311a Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 2 Dec 2023 13:52:23 +0000 Subject: [PATCH] Support hashtags, mentions and code.
 still to do.

---
 text.py | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 53 insertions(+), 7 deletions(-)

diff --git a/text.py b/text.py
index a99a61d..976a255 100644
--- a/text.py
+++ b/text.py
@@ -40,6 +40,9 @@ class ColouredString:
         else:
             return f"ColouredString({self.s!r}, {self.c!r})"
 
+    def __iter__(self):
+        return (ColouredString(sc, cc) for sc, cc in zip(self.s, self.c))
+
     def __eq__(self, rhs):
         rhs = type(self)(rhs)
         return (self.s, self.c) == (rhs.s, rhs.c)
@@ -56,6 +59,9 @@ class ColouredString:
                     'S': '\033[0;1;7;44;37m',
                     'D': '\033[0;7;44;37m',
                     'F': '\033[0;1;32m',
+                    'c': '\033[0;33m',
+                    '#': '\033[0;36m',
+                    '@': '\033[0;32m',
                 }[cc])
                 colour = cc
             buf.write(sc)
@@ -133,11 +139,19 @@ class HTMLParser(html.parser.HTMLParser):
     def __init__(self):
         super().__init__()
         self.paras = [Paragraph()]
+        self.colourstack = [' ']
 
     def handle_starttag(self, tag, attrs):
-        if tag in {"a", "span"}:
-            # FIXME: maybe handle some cases of this to spot hashtags,
-            # usernames etc?
+        attrdict = dict(attrs)
+
+        if tag == "a":
+            classes = set(attrdict.get("class", "").split())
+            colour = ("#" if "hashtag" in classes else
+                      "@" if "mention" in classes else " ")
+            self.colourstack.append(colour)
+            return
+
+        if tag == "span":
             return
 
         if tag == "p":
@@ -150,10 +164,19 @@ class HTMLParser(html.parser.HTMLParser):
             self.paras.append(Paragraph())
             return
 
+        if tag == "code":
+            self.colourstack.append('c')
+            return
+
+        # FIXME: need 
, e.g. in
+        # https://neuromatch.social/@mstimberg/111375114784712346
+        # and _perhaps_ that ought to generate paragraphs with a
+        # 'truncate, don't wrap' attribute?
+
         print("UNKNOWN START", tag, attrs)
 
     def handle_endtag(self, tag):
-        if tag in {"a", "span"}:
+        if tag == "span":
             return
 
         if tag == "p":
@@ -161,8 +184,12 @@ class HTMLParser(html.parser.HTMLParser):
                 self.paras.append(Paragraph())
             return
 
+        if tag in {"a", "code"}:
+            self.colourstack.pop()
+            return
+
     def handle_data(self, data):
-        self.paras[-1].add(data)
+        self.paras[-1].add(ColouredString(data, self.colourstack[-1]))
 
     def done(self):
         for para in self.paras:
@@ -198,7 +225,7 @@ class RenderTests(unittest.TestCase):
         return list(itertools.chain(*[para.render(width)
                                       for para in pp.paras]))
 
-    def testHTML(self):
+    def testParagraphs(self):
         html = "

Testing, testing, 1, 2, 3

" self.assertEqual(self.parse_html(html), [ ColouredString('Testing, testing, 1, 2, 3'), @@ -217,10 +244,29 @@ class RenderTests(unittest.TestCase): ColouredString('Second line'), ]) - def testWrap(self): + def testWrapping(self): html = ("

Pease porridge hot, pease porridge cold, pease porridge " "in the pot, nine days old

") self.assertEqual(self.parse_html(html), [ ColouredString('Pease porridge hot, pease porridge cold, pease'), ColouredString('porridge in the pot, nine days old'), ]) + + def testMarkup(self): + html = "

Test of some literal code

" + self.assertEqual(self.parse_html(html), [ + ColouredString('Test of some literal code', + ' cccccccccccc'), + ]) + + html = """

Test of a #hashtag

""" + self.assertEqual(self.parse_html(html), [ + ColouredString('Test of a #hashtag', + ' ########'), + ]) + + html = """

Test of a @username

""" + self.assertEqual(self.parse_html(html), [ + ColouredString('Test of a @username', + ' @@@@@@@@@'), + ]) -- 2.30.2