]>
jfr.im git - irc/weechat/qweechat.git/blob - qweechat/weechat/color.py
1 # -*- coding: utf-8 -*-
3 # color.py - remove/replace colors in WeeChat strings
5 # Copyright (C) 2011-2021 Sébastien Helleu <flashcode@flashtux.org>
7 # This file is part of QWeeChat, a Qt remote GUI for WeeChat.
9 # QWeeChat is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
14 # QWeeChat is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with QWeeChat. If not, see <http://www.gnu.org/licenses/>.
26 RE_COLOR_ATTRS
= r
'[*!/_|]*'
27 RE_COLOR_STD
= r
'(?:%s\d{2})' % RE_COLOR_ATTRS
28 RE_COLOR_EXT
= r
'(?:@%s\d{5})' % RE_COLOR_ATTRS
29 RE_COLOR_ANY
= r
'(?:%s|%s)' % (RE_COLOR_STD
, RE_COLOR_EXT
)
30 # \x19: color code, \x1A: set attribute, \x1B: remove attribute, \x1C: reset
31 RE_COLOR
= re
.compile(
32 r
'(\x19(?:\d{2}|F%s|B\d{2}|B@\d{5}|E|\\*%s(,%s)?|@\d{5}|b.|\x1C))|\x1A.|'
34 % (RE_COLOR_ANY
, RE_COLOR_ANY
, RE_COLOR_ANY
))
37 '000000cd000000cd00cdcd000000cdcd00cd00cdcde5e5e5' \
38 '4d4d4dff000000ff00ffff000000ffff00ff00ffffffffff' \
39 '00000000002a0000550000800000aa0000d4002a00002a2a' \
40 '002a55002a80002aaa002ad400550000552a005555005580' \
41 '0055aa0055d400800000802a0080550080800080aa0080d4' \
42 '00aa0000aa2a00aa5500aa8000aaaa00aad400d40000d42a' \
43 '00d45500d48000d4aa00d4d42a00002a002a2a00552a0080' \
44 '2a00aa2a00d42a2a002a2a2a2a2a552a2a802a2aaa2a2ad4' \
45 '2a55002a552a2a55552a55802a55aa2a55d42a80002a802a' \
46 '2a80552a80802a80aa2a80d42aaa002aaa2a2aaa552aaa80' \
47 '2aaaaa2aaad42ad4002ad42a2ad4552ad4802ad4aa2ad4d4' \
48 '55000055002a5500555500805500aa5500d4552a00552a2a' \
49 '552a55552a80552aaa552ad455550055552a555555555580' \
50 '5555aa5555d455800055802a5580555580805580aa5580d4' \
51 '55aa0055aa2a55aa5555aa8055aaaa55aad455d40055d42a' \
52 '55d45555d48055d4aa55d4d480000080002a800055800080' \
53 '8000aa8000d4802a00802a2a802a55802a80802aaa802ad4' \
54 '80550080552a8055558055808055aa8055d480800080802a' \
55 '8080558080808080aa8080d480aa0080aa2a80aa5580aa80' \
56 '80aaaa80aad480d40080d42a80d45580d48080d4aa80d4d4' \
57 'aa0000aa002aaa0055aa0080aa00aaaa00d4aa2a00aa2a2a' \
58 'aa2a55aa2a80aa2aaaaa2ad4aa5500aa552aaa5555aa5580' \
59 'aa55aaaa55d4aa8000aa802aaa8055aa8080aa80aaaa80d4' \
60 'aaaa00aaaa2aaaaa55aaaa80aaaaaaaaaad4aad400aad42a' \
61 'aad455aad480aad4aaaad4d4d40000d4002ad40055d40080' \
62 'd400aad400d4d42a00d42a2ad42a55d42a80d42aaad42ad4' \
63 'd45500d4552ad45555d45580d455aad455d4d48000d4802a' \
64 'd48055d48080d480aad480d4d4aa00d4aa2ad4aa55d4aa80' \
65 'd4aaaad4aad4d4d400d4d42ad4d455d4d480d4d4aad4d4d4' \
66 '0808081212121c1c1c2626263030303a3a3a4444444e4e4e' \
67 '5858586262626c6c6c7676768080808a8a8a9494949e9e9e' \
68 'a8a8a8b2b2b2bcbcbcc6c6c6d0d0d0dadadae4e4e4eeeeee'
70 # WeeChat basic colors (color name, index in terminal colors)
71 WEECHAT_BASIC_COLORS
= (
72 ('default', 0), ('black', 0), ('darkgray', 8), ('red', 1),
73 ('lightred', 9), ('green', 2), ('lightgreen', 10), ('brown', 3),
74 ('yellow', 11), ('blue', 4), ('lightblue', 12), ('magenta', 5),
75 ('lightmagenta', 13), ('cyan', 6), ('lightcyan', 14), ('gray', 7),
79 log
= logging
.getLogger(__name__
)
83 def __init__(self
, color_options
, debug
=False):
84 self
.color_options
= color_options
87 def _rgb_color(self
, index
):
88 color
= TERMINAL_COLORS
[index
*6:(index
*6)+6]
89 r
= int(color
[0:2], 16) * 0.85
90 g
= int(color
[2:4], 16) * 0.85
91 b
= int(color
[4:6], 16) * 0.85
92 return '%02x%02x%02x' % (r
, g
, b
)
94 def _convert_weechat_color(self
, color
):
97 return '\x01(Fr%s)' % self
.color_options
[index
]
99 log
.debug('Error decoding WeeChat color "%s"' % color
)
102 def _convert_terminal_color(self
, fg_bg
, attrs
, color
):
105 return '\x01(%s%s#%s)' % (fg_bg
, attrs
, self
._rgb
_color
(index
))
107 log
.debug('Error decoding terminal color "%s"' % color
)
110 def _convert_color_attr(self
, fg_bg
, color
):
112 if color
[0].startswith('@'):
117 while color
.startswith(('*', '!', '/', '_', '|')):
118 # TODO: manage the "keep attributes" flag
119 # if color[0] == '|':
124 return self
._convert
_terminal
_color
(fg_bg
, attrs
, color
)
127 return self
._convert
_terminal
_color
(fg_bg
, attrs
,
128 WEECHAT_BASIC_COLORS
[index
][1])
130 log
.debug('Error decoding color "%s"' % color
)
133 def _attrcode_to_char(self
, code
):
140 return codes
.get(code
, '')
142 def _convert_color(self
, match
):
143 color
= match
.group(0)
144 if color
[0] == '\x19':
148 elif color
[1] == '\x1C':
150 return '\x01(Fr)\x01(Br)'
151 elif color
[1] in ('F', 'B'):
152 # foreground or background
153 return self
._convert
_color
_attr
(color
[1], color
[2:])
154 elif color
[1] == '*':
155 # foreground with optional background
156 items
= color
[2:].split(',')
157 s
= self
._convert
_color
_attr
('F', items
[0])
159 s
+= self
._convert
_color
_attr
('B', items
[1])
161 elif color
[1] == '@':
162 # direct ncurses pair number, ignored
164 elif color
[1] == 'E':
165 # text emphasis, ignored
167 if color
[1:].isdigit():
168 return self
._convert
_weechat
_color
(int(color
[1:]))
171 elif color
[0] == '\x1A':
173 return '\x01(+%s)' % self
._attrcode
_to
_char
(color
[1])
174 elif color
[0] == '\x1B':
176 return '\x01(-%s)' % self
._attrcode
_to
_char
(color
[1])
177 elif color
[0] == '\x1C':
179 return '\x01(Fr)\x01(Br)'
180 # should never be executed!
181 return match
.group(0)
183 def _convert_color_debug(self
, match
):
184 group
= match
.group(0)
185 for code
in (0x01, 0x02, 0x03, 0x04, 0x19, 0x1A, 0x1B):
186 group
= group
.replace(chr(code
), '<x%02X>' % code
)
189 def convert(self
, text
):
193 return RE_COLOR
.sub(self
._convert
_color
_debug
, text
)
195 return RE_COLOR
.sub(self
._convert
_color
, text
)
199 """Remove colors in a WeeChat string."""
202 return re
.sub(RE_COLOR
, '', text
)