From 92e63829a699ec68e7dcc2185fb7393255342dd2 Mon Sep 17 00:00:00 2001
From: Florent Le Coz <louiz@louiz.org>
Date: Wed, 30 Mar 2011 04:34:45 +0200
Subject: Finish colors support with xhtml (clean the elinks dump, handle the
 input etc)

---
 src/tabs.py    | 10 ++++++++--
 src/windows.py | 20 ++++++++++++++++++-
 src/xhtml.py   | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 85 insertions(+), 8 deletions(-)

(limited to 'src')

diff --git a/src/tabs.py b/src/tabs.py
index b7624c2b..53115716 100644
--- a/src/tabs.py
+++ b/src/tabs.py
@@ -39,6 +39,7 @@ import string
 import common
 import core
 import singleton
+import xhtml
 
 import multiuserchat as muc
 
@@ -270,7 +271,8 @@ class ChatTab(Tab):
 
     def on_enter(self):
         txt = self.input.key_enter()
-        if not self.execute_command(txt):
+        clean_text = xhtml.clean_text(txt)
+        if not self.execute_command(clean_text):
             if txt.startswith('//'):
                 txt = txt[1:]
             self.command_say(txt)
@@ -556,7 +558,11 @@ class MucTab(ChatTab):
     def command_say(self, line):
         msg = self.core.xmpp.make_message(self.get_name())
         msg['type'] = 'groupchat'
-        msg['body'] = line
+        if line.find('\x19') == -1:
+            msg['body'] = line
+        else:
+            msg['body'] = xhtml.clean_text(line)
+            msg['xhtml_im'] = xhtml.poezio_colors_to_html(line)
         if config.get('send_chat_states', 'true') == 'true' and self.remote_wants_chatstates is not False:
             msg['chat_state'] = 'active'
         msg.send()
diff --git a/src/windows.py b/src/windows.py
index 7051bf2d..48cfc7ba 100644
--- a/src/windows.py
+++ b/src/windows.py
@@ -1103,7 +1103,8 @@ class MessageInput(Input):
         """
         attr_char = read_char(self.core.stdscr)
         if attr_char in self.text_attributes or attr_char.isdigit():
-            self.do_command('\x19%s' % attr_char)
+            self.do_command('\x19', False)
+            self.do_command(attr_char)
 
     def key_down(self):
         """
@@ -1131,6 +1132,23 @@ class MessageInput(Input):
         self.clear_text()
         return txt
 
+    def rewrite_text(self):
+        """
+        Refresh the line onscreen, from the pos and pos_line, with colors
+        """
+        with g_lock:
+            text = self.text.replace('\n', '|')
+            self._win.erase()
+            if self.color:
+                self._win.attron(common.curses_color_pair(self.color))
+            displayed_text = text[self.line_pos:self.line_pos+self.width-1]
+            self._win.attrset(0)
+            self.addstr_colored(displayed_text)
+            self.addstr(0, wcwidth.wcswidth(displayed_text[:self.pos]), '')
+            if self.color:
+                self._win.attroff(common.curses_color_pair(self.color))
+            self._refresh()
+
 class CommandInput(Input):
     """
     An input with an help message in the left, with three given callbacks:
diff --git a/src/xhtml.py b/src/xhtml.py
index be09442b..aa2643f5 100644
--- a/src/xhtml.py
+++ b/src/xhtml.py
@@ -32,6 +32,8 @@ log = logging.getLogger(__name__)
 
 
 shell_colors_re = re.compile(r'(\[(?:\d+;)*(?:\d+m))')
+start_indent_re = re.compile(r'\[0;30m\[0;37m   ')
+newline_indent_re = re.compile('\n\[0;37m   ')
 
 def get_body_from_message_stanza(message):
     """
@@ -49,9 +51,24 @@ def get_body_from_message_stanza(message):
             return shell_colors_to_poezio_colors(shell_body)
     return message['body']
 
+def clean_text(string):
+    """
+    Remove all \x19 from the string
+    """
+    pos = string.find('\x19')
+    while pos != -1:
+        string = string[:pos] + string[pos+2:]
+        pos = string.find('\x19')
+    return string
+
 number_to_color_names = {
     1: 'red',
     2: 'green',
+    3: 'yellow',
+    4: 'blue',
+    5: 'violet',
+    6: 'turquoise',
+    7: 'white'
 }
 
 def poezio_colors_to_html(string):
@@ -64,7 +81,7 @@ def poezio_colors_to_html(string):
     # a list of all opened elements, e.g. ['strong', 'span']
     # So that we know what we need to close
     opened_elements = []
-    res = "<body xmlns='http://www.w3.org/1999/html'><p>"
+    res = "<body xmlns='http://www.w3.org/1999/xhtml'><p>"
     next_attr_char = string.find('\x19')
     while next_attr_char != -1:
         attr_char = string[next_attr_char+1].lower()
@@ -101,6 +118,7 @@ def shell_colors_to_poezio_colors(string):
 
     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
 
     """
@@ -110,11 +128,20 @@ def shell_colors_to_poezio_colors(string):
         res = ''
         for num in numbers:
             if num == 0:
-                res += r'\x19o'
-            elif num >= 30 and num <= 37:
-                res += r'\x19%s' % (num-30,)
+                res += '\x19o'
+            elif num == 1:
+                res += '\x19b'
+            elif num >= 31 and num <= 37:
+                res += '\x19%s' % (num-30,)
         return res
-    return shell_colors_re.sub(repl, string)
+    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):
     """
@@ -125,6 +152,32 @@ def xhtml_code_to_shell_colors(string):
     result = process.communicate(input=string.encode('utf-8'))[0]
     return result.decode('utf-8').strip()
 
+def poezio_colors_to_xhtml(string):
+    """
+    Generate a valid xhtml string from
+    the poezio colors in the given string
+    """
+    res = "<body xmlns='http://www.w3.org/1999/xhtml'>"
+    next_attr_char = string.find('\x19')
+    open_elements = []
+    while next_attr_char != -1:
+        attr_char = string[next_attr_char+1].lower()
+        if next_attr_char != 0:
+            res += string[:next_attr_char]
+        string = string[next_attr_char+2:]
+        if attr_char == 'o':
+            # close all opened elements
+            for elem in open_elements:
+                res += '</%s>'
+            open_elements = []
+        elif attr_char == 'b':
+            if 'strong' not in open_elements:
+                res += '<strong>'
+                open_elements.append('strong')
+        elif attr_char.isdigit():
+            self._win.attron(common.curses_color_pair(int(attr_char)))
+        next_attr_char = string.find('\x19')
+
 if __name__ == '__main__':
 #     print(xhtml_code_to_shell_colors("""
 #   <html xmlns='http://jabber.org/protocol/xhtml-im'>
-- 
cgit v1.2.3