From nobody Tue May 13 19:26:18 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 66.187.233.73 as permitted sender) smtp.mailfrom=famz@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by mx.zohomail.com with SMTPS id 151970044198259.82419755270769; Mon, 26 Feb 2018 19:00:41 -0800 (PST) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B264940FB648 for ; Tue, 27 Feb 2018 03:00:40 +0000 (UTC) Received: from localhost (ovpn-12-53.pek2.redhat.com [10.72.12.53]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1431D1C73A for ; Tue, 27 Feb 2018 03:00:39 +0000 (UTC) Received: by 10.80.147.22 with SMTP id m22csp3573030eda; Mon, 26 Feb 2018 03:29:37 -0800 (PST) Received: from mx1.redhat.com (mx3-rdu2.redhat.com. [66.187.233.73]) by mx.google.com with ESMTPS id m15si8295582qti.261.2018.02.26.03.27.28 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 26 Feb 2018 03:27:28 -0800 (PST) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id AB7D84026789 for ; Mon, 26 Feb 2018 11:27:28 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id A699C2026E04; Mon, 26 Feb 2018 11:27:28 +0000 (UTC) Received: from donizetti.redhat.com (ovpn-117-126.ams2.redhat.com [10.36.117.126]) by smtp.corp.redhat.com (Postfix) with ESMTP id 12C032026DFD; Mon, 26 Feb 2018 11:27:27 +0000 (UTC) Resent-From: Fam Zheng Resent-Date: Tue, 27 Feb 2018 11:00:38 +0800 Resent-Message-ID: <20180227030038.GH21035@lemon.usersys.redhat.com> Resent-To: importer@patchew.org X-Google-Smtp-Source: AG47ELuF9OAqtiFcfQaLGd5Pn9VkztryEwZE+FRZl6uA1IZYOzL1uPIUQVOTF2k+cXd2AR9OCaOu X-Received: by 10.55.154.207 with SMTP id c198mr16535061qke.313.1519644448979; Mon, 26 Feb 2018 03:27:28 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519644448; cv=none; d=google.com; s=arc-20160816; b=O0m1x/xptY41PRZTQcez/6XlTI/HUvqBPZg2k4+9p72V5J6WTMgv0EC4NuQAbVrcpd W3BYkqovSNrIRwbMQCTl8bufCnsE8MYWpslDNZmR+dmMJgYs3Fy8ZsBL/LC/geyFKNFj J6uJ0fwEue1MlT3FKk59JNYCptXcz59z8FlzwuGyJWt01SdovC0auHGvlXq7Nnpbal5t gSXIt4VaFDe6Y161t1+ESyasVomGuMAL7lCgolMADNo/W+o4rLhb2rIwE4j8VtfevUQt xBPAcFCDO0INgot5ibsl3ay/VdO66MzPwxEcXmPpPvtxNCt6fpOv3gpyTkmGWGLwk6dr 23Dw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :delivered-to:arc-authentication-results; bh=kQZZvjh/1kfhRkY8aEtOPtijH196WkeASEv0QQyLJEc=; b=NoFwCIZDALuo2oAHwXFRARbbjtBxd2ardZn7eRDKyVsOrvuu6SLvunsnaRMhYObc/t GrMLFMetr/yZpkauZQoL1p5TDystq0h28Mzkc3Vk6N7T5Vq7bJciPvnoqFVT+jpP5Rx3 3Qk5af2Cawy8K/HRGxF6XrARFXGIYRNE43Yg3In0YwEcZabUUXvphWTgvMQzn5CZ19ZB RFW07Zr9oSzFo1RMjiH4+Nh9CEE21E43VAaSqMtTq2H6vZLOjpvyMvWIP3GbAnFujxtF MqPyQkbV/4LJGREu6SKLjq53xkxF//xzAn5CgcIIclTq4M9UCja5HYmEHMK8itoXwh1D FwKg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain gapps.redhat.com configured 66.187.233.73 as internal address) smtp.mailfrom=pbonzini@redhat.com Received-SPF: pass (zoho.com: domain of redhat.com designates 66.187.233.73 as permitted sender) client-ip=66.187.233.73; envelope-from=famz@redhat.com; helo=mx1.redhat.com; Received-SPF: pass (google.com: domain gapps.redhat.com configured 66.187.233.73 as internal address) Authentication-Results: mx.google.com; spf=pass (google.com: domain gapps.redhat.com configured 66.187.233.73 as internal address) smtp.mailfrom=pbonzini@redhat.com From: Paolo Bonzini To: patchew-devel@freelists.org Cc: famz@redhat.com Subject: [PATCH 6/9] ansi2html: add logic to track formatting per-character Date: Mon, 26 Feb 2018 12:27:19 +0100 Message-Id: <20180226112722.19488-7-pbonzini@redhat.com> In-Reply-To: <20180226112722.19488-1-pbonzini@redhat.com> References: <20180226112722.19488-1-pbonzini@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Mon, 26 Feb 2018 11:27:28 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Mon, 26 Feb 2018 11:27:28 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'pbonzini@redhat.com' RCPT:'' X-TUID: aQk8dOG/Jm5P X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 27 Feb 2018 03:00:40 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 27 Feb 2018 03:00:40 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'famz@redhat.com' RCPT:'' X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Add the code to track formatting within a line and write out HTML tags. Signed-off-by: Paolo Bonzini --- patchew/logviewer.py | 56 +++++++++++++++++++++++++++++++++++++++++-------= ---- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/patchew/logviewer.py b/patchew/logviewer.py index b5627fa..b8d558d 100644 --- a/patchew/logviewer.py +++ b/patchew/logviewer.py @@ -38,32 +38,39 @@ class ANSI2HTMLConverter(object): RE_ENTITIES =3D re.compile('[\x00-\x1F<>&\x7F]') =20 def __init__(self, white_bg=3DFalse): + self.class_to_id =3D {} + self.id_to_class =3D [] + self.cur_class =3D self._class_to_id("") self.prefix =3D '
'
         self._reset()
=20
     def _reset(self):
         self.line =3D []
+        self.class_ids =3D []
         self.pos =3D 0
         self.lazy_contents =3D ''
         self.lazy_accumulate =3D True
=20
-    # self.line holds the characters for the current line.
-    # Writing can overwrite some characters if self.pos is
-    # not pointing to the end of the line, and then appends.
-    # Moving the cursor right can add spaces to the end.
+    # self.line and self.class_ids hold the characters and style respectiv=
ely
+    # for the current line.  Writing can overwrite some characters if self=
.pos
+    # is not pointing to the end of the line, and then appends.  Moving the
+    # cursor right can add spaces to the end, but those are never styled.
=20
-    def _write(self, chars):
+    def _write(self, chars, class_id):
         assert not self.lazy_accumulate or self.lazy_contents =3D=3D ''
         self.lazy_accumulate =3D False
+        classes =3D [class_id] * len(chars)
         cur_len =3D len(self.line)
         if self.pos < cur_len:
             last =3D min(cur_len - self.pos, len(chars))
             self.line[self.pos:self.pos+last] =3D list(chars[0:last])
+            self.class_ids[self.pos:self.pos+last] =3D classes[0:last]
         else:
             last =3D 0
=20
         if len(chars) > last:
             self.line +=3D list(chars[last:])
+            self.class_ids +=3D classes[last:]
         self.pos +=3D len(chars)
=20
     def _set_pos(self, pos):
@@ -73,29 +80,52 @@ class ANSI2HTMLConverter(object):
             self.lazy_accumulate =3D False
             num =3D self.pos - len(self.line)
             self.line +=3D [' '] * num
+            self.class_ids +=3D [0] * num
=20
     def _write_prefix(self):
         if self.prefix !=3D '':
             yield self.prefix
             self.prefix =3D ''
=20
-    def _write_span(self, text):
+    def _write_span(self, text, class_id):
+        if class_id > 0:
+            yield ('' % self.id_to_class[class_id])
         yield self.RE_ENTITIES.sub(lambda x: self.ENTITIES[x.group(0)], te=
xt)
+        if class_id > 0:
+            yield ''
+
+    # Flushing a line locates spans that have the same style, and prints t=
hose
+    # with a  tag if they are styled.
=20
     def _write_line(self, suffix):
         # If the line consists of a single string of text without no escap=
es
         # or control chararcters, convert() special cases it
         if self.lazy_contents !=3D '':
-            yield from self._write_span(self.lazy_contents)
+            yield from self._write_span(self.lazy_contents, self.cur_class)
             yield suffix
             self._reset()
             return
=20
-        text =3D "".join(self.line)
-        yield from self._write_span(text)
+        self.class_ids.append(-1)
+        start =3D 0
+        class_id =3D self.class_ids[0]
+        for i in range(1, len(self.class_ids)):
+            if self.class_ids[i] !=3D class_id:
+                text =3D "".join(self.line[start:i])
+                yield from self._write_span(text, class_id)
+                start =3D i
+                class_id =3D self.class_ids[i]
         yield suffix
         self._reset()
=20
+    def _class_to_id(self, html_class):
+        class_id =3D self.class_to_id.get(html_class, None)
+        if class_id is None:
+            class_id =3D len(self.class_to_id)
+            self.class_to_id[html_class] =3D class_id
+            self.id_to_class.append(html_class)
+        return class_id
+
     def _do_csi_C(self, it):
         arg =3D next(it)
         if arg =3D=3D 0:
@@ -115,11 +145,13 @@ class ANSI2HTMLConverter(object):
             if self.pos < len(self.line):
                 assert not self.lazy_accumulate
                 del self.line[self.pos:]
+                del self.class_ids[self.pos:]
         if arg =3D=3D 1 or arg =3D=3D 2:
             save_pos =3D self.pos
             if save_pos > 0:
                 self.pos =3D 0
-                self._write(' ' * save_pos)
+                # clearing to the beginning of the line uses unstyled spac=
es
+                self._write(' ' * save_pos, 0)
=20
     def _parse_csi_with_args(self, csi, func):
         if (len(csi) <=3D 3):
@@ -151,7 +183,7 @@ class ANSI2HTMLConverter(object):
                 if self.lazy_accumulate:
                     self.lazy_contents +=3D m.group(1)
                 else:
-                    self._write(m.group(1))
+                    self._write(m.group(1), self.cur_class)
             else:
                 seq =3D m.group(2)
                 # _write_line can deal with lazy storage.  Everything else
@@ -166,7 +198,7 @@ class ANSI2HTMLConverter(object):
                 if self.lazy_contents !=3D '':
                     content =3D self.lazy_contents
                     self.lazy_contents =3D ''
-                    self._write(content)
+                    self._write(content, self.cur_class)
=20
                 if seq =3D=3D '\b':
                     if self.pos > 0:
--=20
2.14.3