From nobody Sat Apr 20 08:41:39 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=patchew-devel-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=patchew-devel-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1520496056919932.2665132951437; Thu, 8 Mar 2018 00:00:56 -0800 (PST) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 0DCA9356DD; Thu, 8 Mar 2018 08:00:56 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 020B66134B; Thu, 8 Mar 2018 08:00:56 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id EE31A4CA99; Thu, 8 Mar 2018 08:00:55 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w2880swN032370 for ; Thu, 8 Mar 2018 03:00:54 -0500 Received: by smtp.corp.redhat.com (Postfix) id 3C43917996; Thu, 8 Mar 2018 08:00:54 +0000 (UTC) Received: from mx1.redhat.com (ext-mx06.extmail.prod.ext.phx2.redhat.com [10.5.110.30]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 34ABC614D0 for ; Thu, 8 Mar 2018 08:00:51 +0000 (UTC) Received: from mail-wm0-f68.google.com (mail-wm0-f68.google.com [74.125.82.68]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CE5A7285CF for ; Thu, 8 Mar 2018 08:00:48 +0000 (UTC) Received: by mail-wm0-f68.google.com with SMTP id t3so9469470wmc.2 for ; Thu, 08 Mar 2018 00:00:48 -0800 (PST) Received: from donizetti.lan (94-36-191-219.adsl-ull.clienti.tiscali.it. [94.36.191.219]) by smtp.gmail.com with ESMTPSA id b9sm21755912wrh.68.2018.03.08.00.00.45 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 08 Mar 2018 00:00:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=xMux4HtlHc5yORzLzkJhaeITJ9S4pkotopj5COMdbWg=; b=Pqdwei7rEoiTs5/AohlV5glWQRh6CcPrGYmx4ddq3w1N2Ts1o8GDPI+20rtVnkMz7p N3QLXiKCmBiYNv9yL3wE3xr4yOA2dTmKJhELbOrmKnPX3bQqjCBj7XkOn5tN5+EmG9Uw rPmyaBH4ZYGfmImfdx5Wz0iK5vzDJ8J06Z+2tf2MAdMD6S6PqOphNHTer7hdFm/TcG2z v57g96gx0y7LmhmH+wXMp3Bo6Dtl/7eygyRjipPUGUr7P84dbl8k++W82wh8oeylE4+o PvkeVnpjo3H9iGkWIgdtoLxEBp7Wh4pjxSXFVXpR/WQYfrbdvvo/iRzMUdmcrbnvxrIJ hQmw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references; bh=xMux4HtlHc5yORzLzkJhaeITJ9S4pkotopj5COMdbWg=; b=FBeFyq2xQ0kdQQ4UoVhaLeRstCO0hNmkqkG4t1esCP9tZw2GxKwradu6VlpSzWGABD qAnWOGPTodliRytsE8lpecnAc+8AW5jm9LKEHSZXMMYVjJtochkN/HG7avu0OjStJ/CB qKkcAvbCtgPyayZW6V/EeX3aC+WxA6xB+b7vDzn6oqZLWrw9UKwsc9LphnXVaCh2xZ0B 1Pp9/DhJHzhxk3eerAViKR1wNf6mPeTdLSIkXa5EFhowXj5S60CLYjsK+WxFUiBVRM8B 926i8koyLe1Ko+pY564kwt7FY0uzcC2ovqx5UoKrS6mShUfDEQSd23lIgiOOn3pEO6CC /ZRg== X-Gm-Message-State: AElRT7HYMk0M4GhPobTIJLwWotJJfRY/oj28F8vxsTzd8PDJzA7Re2Rb iHMcC8ENKD6zppokBE36fvwVLnmi X-Google-Smtp-Source: AG47ELtdHjnvlp/wUcaYmoGb6rv4oOSnbdSJlvNRn20Ex+HpknAlvAbXRbSZ6MgcF4zTtOUsjF8n8Q== X-Received: by 10.28.94.11 with SMTP id s11mr16049679wmb.159.1520496046899; Thu, 08 Mar 2018 00:00:46 -0800 (PST) From: Paolo Bonzini To: patchew-devel@redhat.com Date: Thu, 8 Mar 2018 09:00:37 +0100 Message-Id: <20180308080042.19342-3-pbonzini@redhat.com> In-Reply-To: <20180308080042.19342-1-pbonzini@redhat.com> References: <20180308080042.19342-1-pbonzini@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Thu, 08 Mar 2018 08:00:49 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Thu, 08 Mar 2018 08:00:49 +0000 (UTC) for IP:'74.125.82.68' DOMAIN:'mail-wm0-f68.google.com' HELO:'mail-wm0-f68.google.com' FROM:'paolo.bonzini@gmail.com' RCPT:'' X-RedHat-Spam-Score: 0.469 (DKIM_SIGNED, DKIM_VALID, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_PASS) 74.125.82.68 mail-wm0-f68.google.com 74.125.82.68 mail-wm0-f68.google.com X-RedHat-Possible-Forgery: Paolo Bonzini X-Scanned-By: MIMEDefang 2.78 on 10.5.110.30 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-loop: patchew-devel@redhat.com Subject: [Patchew-devel] [PATCH 2/7] ansi2html: create ANSIProcessor superclass X-BeenThere: patchew-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Patchew development and discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: patchew-devel-bounces@redhat.com Errors-To: patchew-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Thu, 08 Mar 2018 08:00:56 +0000 (UTC) X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Paolo Bonzini --- patchew/logviewer.py | 216 ++++++++++++++++++++++++++++-------------------= ---- 1 file changed, 120 insertions(+), 96 deletions(-) diff --git a/patchew/logviewer.py b/patchew/logviewer.py index ab5f5c3..aa5d2bb 100644 --- a/patchew/logviewer.py +++ b/patchew/logviewer.py @@ -15,38 +15,18 @@ from django.views import View from django.http import HttpResponse, StreamingHttpResponse from django.utils.safestring import mark_safe =20 -class ANSI2HTMLConverter(object): +class ANSIProcessor(object): RE_STRING =3D '[^\b\t\n\f\r\x1B]+' RE_NUMS =3D '[0-9]+(?:;[0-9]+)*' RE_CSI =3D r'\[\??(?:' + RE_NUMS + ')?[^;0-9]' RE_OSC =3D r'].*?(?:\x1B\\|\x07)' RE_CONTROL =3D '\x1B(?:%s|%s|[^][])|\r\n|[\b\t\n\f\r]' % (RE_CSI, RE_O= SC) RE =3D re.compile('(%s)|(%s)' % (RE_STRING, RE_CONTROL)) - COLORS =3D [ "BLK", "RED", "GRN", "YEL", "BLU", "MAG", "CYN", "WHI", - "HIK", "HIR", "HIG", "HIY", "HIB", "HIM", "HIC", "HIW" ] - - ENTITIES =3D { - '\x00' : '␀', '\x01' : '␁', '\x02' : '␂', - '\x03' : '␃', '\x04' : '␄', '\x05' : '␅', - '\x06' : '␆', '\x07' : '🔔', '\x0B' : '␋', - '\x0E' : '␎', '\x0F' : '␏', '\x10' : '␐', - '\x11' : '␑', '\x12' : '␒', '\x13' : '␓', - '\x14' : '␔', '\x15' : '␕', '\x16' : '␖', - '\x17' : '␗', '\x18' : '␘', '\x19' : '␙', - '\x1A' : '␚', '\x1B' : '␛', '\x1C' : '␜', - '\x1D' : '␝', '\x1E' : '␞', '\x1F' : '␟', - '<' : '<', '>' : '>', '&' : '&', - '\x7F' : '⌦' - } - RE_ENTITIES =3D re.compile('[\x00-\x1F<>&\x7F]') =20 - def __init__(self, white_bg=3DFalse): + def __init__(self): self.class_to_id =3D {} self.id_to_class =3D [] - self.default_fg =3D 0 if white_bg else 7 - self.default_bg =3D 7 if white_bg else 0 self.cur_class =3D self._class_to_id("") - self.prefix =3D '
'
         self._reset()
         self._reset_attrs()
=20
@@ -99,17 +79,9 @@ class ANSI2HTMLConverter(object):
             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 ''
-
+    @abc.abstractmethod
     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 ''
+        pass
=20
     # Flushing a line locates spans that have the same style, and prints t=
hose
     # with a  tag if they are styled.
@@ -198,7 +170,7 @@ class ANSI2HTMLConverter(object):
             self.bg =3D arg - 92
=20
     def _write_form_feed(self):
-        yield '
' + pass =20 def _class_to_id(self, html_class): class_id =3D self.class_to_id.get(html_class, None) @@ -208,67 +180,8 @@ class ANSI2HTMLConverter(object): self.id_to_class.append(html_class) return class_id =20 - def _map_color(self, color, default, dim): - # map a color assigned by _do_one_csi_m to an index in the COLORS = array - - color =3D color if color is not None else default - if dim: - # must be foreground color - if isinstance(color, int): - # unlike vte which has a "very dark" grey, for simplicity - # dark grey remains dark grey - return 8 if color =3D=3D default or color =3D=3D 8 else co= lor&~8 - else: - return ('d' + color[0], 'd' + color[1]) - else: - if isinstance(color, int): - # use light colors by default, except for black and light = grey - # (but see bold case in _compute_class) - return color if color =3D=3D 0 or color =3D=3D 7 else colo= r|8 - else: - return color - def _compute_class(self): - fg =3D self._map_color(self.fg, self.default_fg, self.dim) - bg =3D self._map_color(self.bg, self.default_bg, False) - - # apply inverse now: "inverse dim" affects the *background* color! - if self.inverse: - fg, bg =3D bg, fg - - # bold turns foreground light grey into white - if fg =3D=3D 7 and not self.dim and self.bold: - fg =3D 15 - - # now compute CSS classes - classes =3D [] - if isinstance(fg, int): - if fg !=3D self.default_fg: - classes.append(self.COLORS[fg]) - else: - # 256-color palette - classes.append(fg[0]) - - if isinstance(bg, int): - if bg !=3D self.default_bg: - classes.append('B' + self.COLORS[bg]) - else: - classes.append(bg[1]) - - if self.bold: - classes.append('BOLD') - if self.italic: - classes.append('ITA') - - if self.underline or self.strike: - undstr =3D '' - if self.underline: - undstr +=3D 'UND' - if self.strike: - undstr +=3D 'STR' - classes.append(undstr) - - self.cur_class =3D self._class_to_id(" ".join(classes)) + pass =20 def _do_csi_m(self, it): try: @@ -335,7 +248,6 @@ class ANSI2HTMLConverter(object): self._parse_csi_with_args(csi, self._do_csi_m) =20 def convert(self, input): - yield from self._write_prefix() for m in self.RE.finditer(input): if m.group(1): if self.lazy_accumulate: @@ -369,11 +281,123 @@ class ANSI2HTMLConverter(object): elif len(seq) > 1: yield from self._parse_csi(seq) =20 + def finish(self): + yield from self._write_line('') + self._reset_attrs() + + +class ANSI2HTMLConverter(ANSIProcessor): + ENTITIES =3D { + '\x00' : '␀', '\x01' : '␁', '\x02' : '␂', + '\x03' : '␃', '\x04' : '␄', '\x05' : '␅', + '\x06' : '␆', '\x07' : '🔔', '\x0B' : '␋', + '\x0E' : '␎', '\x0F' : '␏', '\x10' : '␐', + '\x11' : '␑', '\x12' : '␒', '\x13' : '␓', + '\x14' : '␔', '\x15' : '␕', '\x16' : '␖', + '\x17' : '␗', '\x18' : '␘', '\x19' : '␙', + '\x1A' : '␚', '\x1B' : '␛', '\x1C' : '␜', + '\x1D' : '␝', '\x1E' : '␞', '\x1F' : '␟', + '<' : '<', '>' : '>', '&' : '&', + '\x7F' : '⌦' + } + RE_ENTITIES =3D re.compile('[\x00-\x1F<>&\x7F]') + + COLORS =3D [ "BLK", "RED", "GRN", "YEL", "BLU", "MAG", "CYN", "WHI", + "HIK", "HIR", "HIG", "HIY", "HIB", "HIM", "HIC", "HIW" ] + + def __init__(self, white_bg=3DFalse): + super(ANSI2HTMLConverter, self).__init__() + self.default_fg =3D 0 if white_bg else 7 + self.default_bg =3D 7 if white_bg else 0 + self.prefix =3D '
'
+
+    def _write_prefix(self):
+        if self.prefix !=3D '':
+            yield self.prefix
+            self.prefix =3D ''
+
+    def _map_color(self, color, default, dim):
+        # map a color assigned by _do_one_csi_m to an index in the COLORS =
array
+
+        color =3D color if color is not None else default
+        if dim:
+            # must be foreground color
+            if isinstance(color, int):
+                # unlike vte which has a "very dark" grey, for simplicity
+                # dark grey remains dark grey
+                return 8 if color =3D=3D default or color =3D=3D 8 else co=
lor&~8
+            else:
+                return ('d' + color[0], 'd' + color[1])
+        else:
+            if isinstance(color, int):
+                # use light colors by default, except for black and light =
grey
+                # (but see bold case in _compute_class)
+                return color if color =3D=3D 0 or color =3D=3D 7 else colo=
r|8
+            else:
+                return color
+
+    def _compute_class(self):
+        fg =3D self._map_color(self.fg, self.default_fg, self.dim)
+        bg =3D self._map_color(self.bg, self.default_bg, False)
+
+        # apply inverse now: "inverse dim" affects the *background* color!
+        if self.inverse:
+            fg, bg =3D bg, fg
+
+        # bold turns foreground light grey into white
+        if fg =3D=3D 7 and not self.dim and self.bold:
+            fg =3D 15
+
+        # now compute CSS classes
+        classes =3D []
+        if isinstance(fg, int):
+            if fg !=3D self.default_fg:
+                classes.append(self.COLORS[fg])
+        else:
+            # 256-color palette
+            classes.append(fg[0])
+
+        if isinstance(bg, int):
+            if bg !=3D self.default_bg:
+                classes.append('B' + self.COLORS[bg])
+        else:
+            classes.append(bg[1])
+
+        if self.bold:
+            classes.append('BOLD')
+        if self.italic:
+            classes.append('ITA')
+
+        if self.underline or self.strike:
+            undstr =3D ''
+            if self.underline:
+                undstr +=3D 'UND'
+            if self.strike:
+                undstr +=3D 'STR'
+            classes.append(undstr)
+
+        self.cur_class =3D self._class_to_id(" ".join(classes))
+
+    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 ''
+
+    def _write_form_feed(self):
+        yield '
' + + def convert(self, input): + yield from self._write_prefix() + yield from super(ANSI2HTMLConverter, self).convert(input) + def finish(self): yield from self._write_prefix() - yield from self._write_line('
') + yield from super(ANSI2HTMLConverter, self).finish() + yield '
' self.prefix =3D '
'
-        self._reset_attrs()
+
=20
 def ansi2html(input, white_bg=3DFalse):
     c =3D ANSI2HTMLConverter(white_bg=3Dwhite_bg)
--=20
2.14.3


_______________________________________________
Patchew-devel mailing list
Patchew-devel@redhat.com
https://www.redhat.com/mailman/listinfo/patchew-devel