diff options
-rw-r--r-- | data/default_config.cfg | 2 | ||||
-rw-r--r-- | src/core.py | 4 | ||||
-rw-r--r-- | src/data_forms.py | 1 | ||||
-rw-r--r-- | src/room.py | 6 | ||||
-rw-r--r-- | src/tabs.py | 20 | ||||
-rw-r--r-- | src/windows.py | 9 | ||||
-rw-r--r-- | src/xhtml.py | 200 |
7 files changed, 146 insertions, 96 deletions
diff --git a/data/default_config.cfg b/data/default_config.cfg index 5e9f35d6..0c16ef97 100644 --- a/data/default_config.cfg +++ b/data/default_config.cfg @@ -47,7 +47,7 @@ completion = normal # a SPACE will always be added after that after_completion = , -# a list of words (separated by a semicolon (:)) that will be +# a list of words (separated by a colon (:)) that will be # highlighted if said by someone on a room highlight_on = diff --git a/src/core.py b/src/core.py index 92a644be..96531e5f 100644 --- a/src/core.py +++ b/src/core.py @@ -884,6 +884,10 @@ class Core(object): self.command_win('%s' % tab.nb) return for tab in self.tabs: + if tab.get_color_state() == theme.COLOR_TAB_DISCONNECTED: + self.command_win('%s' % tab.nb) + return + for tab in self.tabs: if isinstance(tab, tabs.ChatTab) and not tab.input.is_empty(): self.command_win('%s' % tab.nb) return diff --git a/src/data_forms.py b/src/data_forms.py index dc532b87..176c4669 100644 --- a/src/data_forms.py +++ b/src/data_forms.py @@ -63,6 +63,7 @@ class DataFormsTab(Tab): self.form_win.on_input(key) def resize(self): + self.need_resize = False self.topic_win.resize(1, self.width, 0, 0) self.tab_win.resize(1, self.width, self.height-2, 0) self.form_win.resize(self.height-4, self.width, 1, 0) diff --git a/src/room.py b/src/room.py index 58b96adb..83b00e62 100644 --- a/src/room.py +++ b/src/room.py @@ -99,9 +99,10 @@ class Room(TextBuffer): in the room anymore """ self.log_message(txt, time, nickname) + special_message = False if txt.startswith('/me '): txt = "\x192* \x195" + nickname + ' ' + txt[4:] - nickname = None + special_message = True user = self.get_user_by_name(nickname) if nickname is not None else None if user: user.set_last_talked(datetime.now()) @@ -119,6 +120,9 @@ class Room(TextBuffer): highlight = self.do_highlight(txt, time, nickname) if highlight: nick_color = highlight + if special_message: + txt = '\x195%s' % (txt,) + nickname = None time = time or datetime.now() message = Message(txt='%s\x19o'%(txt.replace('\t', ' '),), nick_color=nick_color, time=time, str_time=time.strftime("%Y-%m-%d %H:%M:%S")\ diff --git a/src/tabs.py b/src/tabs.py index 6c819138..3a93f541 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -680,6 +680,7 @@ class MucTab(ChatTab): """ if not self.visible: return + self.need_resize = False text_width = (self.width//10)*9 self.topic_win.resize(1, self.width, 0, 0) self.v_separator.resize(self.height-3, 1, 1, 9*(self.width//10)) @@ -1035,6 +1036,7 @@ class PrivateTab(ChatTab): def resize(self): if self.core.information_win_size >= self.height-3 or not self.visible: return + self.need_resize = False self.text_win.resize(self.height-3-self.core.information_win_size, self.width, 0, 0) self.text_win.rebuild_everything(self._room) self.info_header.resize(1, self.width, self.height-3-self.core.information_win_size, 0) @@ -1123,22 +1125,24 @@ class PrivateTab(ChatTab): """ The user left the associated MUC """ + self.deactivate() if not status_message: self.get_room().add_message(_('\x191%(spec)s \x193%(nick)s\x195 has left the room') % {'nick':from_nick.replace('"', '\\"'), 'spec':theme.CHAR_QUIT.replace('"', '\\"')}) else: self.get_room().add_message(_('\x191%(spec)s \x193%(nick)s\x195 has left the room (%(status)s)"') % {'nick':from_nick.replace('"', '\\"'), 'spec':theme.CHAR_QUIT, 'status': status_message.replace('"', '\\"')}) - self.deactivate() - self.refresh() - self.core.doupdate() + if self.core.current_tab() is self: + self.refresh() + self.core.doupdate() def user_rejoined(self, nick): """ The user (or at least someone with the same nick) came back in the MUC """ - self.get_room().add_message('\x194%(spec)s \x193%(nick)s\x195 joined the room' % {'nick':nick, 'spec':theme.CHAR_JOIN}) self.activate() - self.refresh() - self.core.doupdate() + self.get_room().add_message('\x194%(spec)s \x193%(nick)s\x195 joined the room' % {'nick':nick, 'spec':theme.CHAR_JOIN}) + if self.core.current_tab() is self: + self.refresh() + self.core.doupdate() def activate(self): self.on = True @@ -1184,6 +1188,7 @@ class RosterInfoTab(Tab): def resize(self): if not self.visible: return + self.need_resize = False roster_width = self.width//2 info_width = self.width-roster_width-1 self.v_separator.resize(self.height-2, 1, 0, roster_width) @@ -1540,6 +1545,7 @@ class ConversationTab(ChatTab): def resize(self): if self.core.information_win_size >= self.height-3 or not self.visible: return + self.need_resize = False self.text_win.resize(self.height-4-self.core.information_win_size, self.width, 1, 0) self.text_win.rebuild_everything(self._room) self.upper_bar.resize(1, self.width, 0, 0) @@ -1657,6 +1663,7 @@ class MucListTab(Tab): def resize(self): if not self.visible: return + self.need_resize = False self.upper_message.resize(1, self.width, 0, 0) column_size = {'node-part': (self.width-5)//4, 'name': (self.width-5)//4*3, @@ -1791,6 +1798,7 @@ class SimpleTextTab(Tab): def resize(self): if not self.visible: return + self.need_resize = False self.text_win.resize(self.height-2, self.width, 0, 0) self.input.resize(1, self.width, self.height-1, 0) diff --git a/src/windows.py b/src/windows.py index 74d3b398..ef11107a 100644 --- a/src/windows.py +++ b/src/windows.py @@ -588,9 +588,7 @@ class TextWin(Win): with g_lock: self._win.erase() for y, line in enumerate(lines): - if line is None: - self.write_line_separator() - else: + if line: msg = line.msg if line.start_pos == 0: if msg.nick_color: @@ -606,8 +604,9 @@ class TextWin(Win): self._win.attrset(0) for y, line in enumerate(lines): if not line: - continue - self.write_text(y, (3 if line.msg.nickname else 1) + len(line.msg.str_time)+len(truncate_nick(line.msg.nickname) or ''), line.msg.txt[line.start_pos:line.end_pos]) + self.write_line_separator() + else: + self.write_text(y, (3 if line.msg.nickname else 1) + len(line.msg.str_time)+len(truncate_nick(line.msg.nickname) or ''), line.msg.txt[line.start_pos:line.end_pos]) if y != self.height-1: self.addstr('\n') self._win.attrset(0) diff --git a/src/xhtml.py b/src/xhtml.py index f8272e4f..8f629e3b 100644 --- a/src/xhtml.py +++ b/src/xhtml.py @@ -38,51 +38,126 @@ def get_body_from_message_stanza(message): if config.get('enable_xhtml_im', 'true') == 'true': xhtml_body = message['xhtml_im'] if xhtml_body: - xhtml_body = convert_links_to_plaintext(xhtml_body) - try: - shell_body = xhtml_code_to_shell_colors(xhtml_body) - except OSError: - log.debug('html parsing failed') - else: - return shell_colors_to_poezio_colors(shell_body) + return xhtml_to_poezio_colors(xhtml_body) return message['body'] -def convert_links_to_plaintext(text): - """ - Replace - <a href='URL'>click</a> - by - <url> (click) - in plain text - """ + +def xhtml_to_poezio_colors(text): + def parse_css(css): + def get_color(string): + if value == 'black': + return 0 + if value == 'red': + return 1 + if value == 'green': + return 2 + if value == 'yellow': + return 3 + if value == 'blue': + return 4 + if value == 'magenta': + return 5 + if value == 'cyan': + return 6 + if value == 'white': + return 7 + if value == 'default': + return 8 + shell = '' + rules = css.split(';') + for rule in rules: + key, value = rule.split(':', 1) + key = key.strip() + value = value.strip() + log.debug(value) + if key == 'background-color': + pass#shell += '\x191' + elif key == 'color': + shell += '\x19%d' % get_color(value) + elif key == 'font-style': + shell += '\x19i' + elif key == 'font-weight': + shell += '\x19b' + elif key == 'margin-left': + shell += ' ' + elif key == 'text-align': + pass + elif key == 'text-decoration': + if value == 'underline': + shell += '\x19u' + elif value == 'blink': + shell += '\x19a' + return shell + log.debug(text) - xml = ElementTree(ET.fromstring(text)) - for parent in xml.getiterator(): - previous_child = None - for child in parent: - if child.tag == '{http://www.w3.org/1999/xhtml}a': - if child.attrib['href'] != child.text: - if child.text is None and 'title' in child.attrib: - link_text = '\n%s (%s)' % (child.attrib['href'], child.attrib['title']) - else: - link_text = '\n%s (%s)' % (child.attrib['href'], child.text) - else: - link_text = child.text - if previous_child is not None: - if previous_child.tail is None: - previous_child.tail = link_text - else: - previous_child.tail += link_text - else: - if parent.text is None: - parent.text = link_text - else: - parent.text += link_text - parent.remove(child) - previous_child = child - if version_info.minor <= 1: - return ET.tostring(xml.getroot()) - return ET.tostring(xml.getroot(), encoding=str) + xml = ET.fromstring(text) + message = '' + for elem in xml.iter(): + if elem.tag == '{http://www.w3.org/1999/xhtml}a': + if 'href' in elem.attrib and elem.attrib['href'] != elem.text: + message += '\x19u%s\x19o (%s)' % (elem.attrib['href'], elem.text) + else: + message += '\x19u' + elem.text + '\x19o' + elif elem.tag == '{http://www.w3.org/1999/xhtml}blockquote': + message += '“' + elif elem.tag == '{http://www.w3.org/1999/xhtml}body': + pass + elif elem.tag == '{http://www.w3.org/1999/xhtml}br': + message += '\n' + elif elem.tag == '{http://www.w3.org/1999/xhtml}cite': + message += '\x19u' + elif elem.tag == '{http://www.w3.org/1999/xhtml}em': + message += '\x19i' + elif elem.tag == '{http://www.w3.org/1999/xhtml}img' and 'src' in elem.attrib: + if elem.attrib['alt']: + message += '%s (%s)' % (elem.attrib['src'], elem.attrib['alt']) + else: + message += elem.attrib['src'] + elif elem.tag == '{http://www.w3.org/1999/xhtml}li': + pass + elif elem.tag == '{http://www.w3.org/1999/xhtml}ol': + pass + elif elem.tag == '{http://www.w3.org/1999/xhtml}p': + pass + elif elem.tag == '{http://www.w3.org/1999/xhtml}span': + pass + elif elem.tag == '{http://www.w3.org/1999/xhtml}strong': + message += '\x19b' + elif elem.tag == '{http://www.w3.org/1999/xhtml}ul': + pass + + if ('style' in elem.attrib and elem.tag != '{http://www.w3.org/1999/xhtml}br' + and elem.tag != '{http://www.w3.org/1999/xhtml}em' + and elem.tag != '{http://www.w3.org/1999/xhtml}strong'): + message += parse_css(elem.attrib['style']) + + if (elem.text and elem.tag != '{http://www.w3.org/1999/xhtml}a' + and elem.tag != '{http://www.w3.org/1999/xhtml}br' + and elem.tag != '{http://www.w3.org/1999/xhtml}img'): + message += elem.text + + if ('style' in elem.attrib and elem.tag != '{http://www.w3.org/1999/xhtml}br' + and elem.tag != '{http://www.w3.org/1999/xhtml}em' + and elem.tag != '{http://www.w3.org/1999/xhtml}strong'): + message += '\x19o' + + if elem.tag == '{http://www.w3.org/1999/xhtml}blockquote': + message += '”' + elif elem.tag == '{http://www.w3.org/1999/xhtml}cite': + message += '\x19o' + elif elem.tag == '{http://www.w3.org/1999/xhtml}em': + message += '\x19o' + elif elem.tag == '{http://www.w3.org/1999/xhtml}strong' or elem.tag == '{http://www.w3.org/1999/xhtml}b': + message += '\x19o' + elif elem.tag == '{http://www.w3.org/1999/xhtml}u': + message += '\x19o' + + if 'title' in elem.attrib: + message += ' [' + elem.attrib['title'] + ']' + + if elem.tail: + message += elem.tail + return message def clean_text(string): @@ -148,47 +223,6 @@ def poezio_colors_to_html(string): res += "</p></body>" return res.replace('\n', '<br />') -def shell_colors_to_poezio_colors(string): - """ - 'shell colors' means something like: - - Bonjour ^[[0;32msalut^[[0m - - The current understanding of this syntax is: - n = 0: reset all attributes to defaults - n = 1: activate bold - n >= 30 and n <= 37: set the foreground to n-30 - - """ - def repl(matchobj): - exp = matchobj.group(0)[2:-1] - numbers = [int(nb) for nb in exp.split(';')] - res = '' - for num in numbers: - if num == 0: - res += '\x19o' - elif num == 1: - res += '\x19b' - elif num >= 31 and num <= 37: - res += '\x19%d' % ((num-30)%7,) - return res - def remove_elinks_indent(string): - lines = string.split('\n') - for i, line in enumerate(lines): - lines[i] = re.sub(' ', '', line, 1) - return '\n'.join(lines) - res = shell_colors_re.sub(repl, string).strip() - res = remove_elinks_indent(res) - return res - -def xhtml_code_to_shell_colors(string): - """ - Use a console browser to parse the xhtml and - make it return a shell-colored string - """ - process = subprocess.Popen(["elinks", "-dump", "-dump-color-mode", "2"], stdout=subprocess.PIPE, stdin=subprocess.PIPE) - result = process.communicate(input=string.encode('utf-8'))[0] - return result.decode('utf-8').strip() def poezio_colors_to_xhtml(string): """ |