summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/themes/dark2
-rw-r--r--data/themes/poezio2
-rw-r--r--src/core.py4
-rw-r--r--src/room.py31
-rw-r--r--src/tabs.py40
-rw-r--r--src/text_buffer.py11
-rw-r--r--src/theme.py2
-rw-r--r--src/wcwidth.py18
-rw-r--r--src/windows.py44
9 files changed, 97 insertions, 57 deletions
diff --git a/data/themes/dark b/data/themes/dark
index 1fa9ed00..a7612c0b 100644
--- a/data/themes/dark
+++ b/data/themes/dark
@@ -4,7 +4,7 @@
# Message text color
COLOR_NORMAL_TEXT = 0
COLOR_INFORMATION_TEXT = 5
-COLOR_HIGHLIGHT_TEXT = 3
+COLOR_HIGHLIGHT_NICK = 46
# User list color
COLOR_USER_VISITOR = 7
diff --git a/data/themes/poezio b/data/themes/poezio
index c5556280..facf68c8 100644
--- a/data/themes/poezio
+++ b/data/themes/poezio
@@ -4,7 +4,7 @@
# Message text color
COLOR_NORMAL_TEXT = 0
COLOR_INFORMATION_TEXT = 5
-COLOR_HIGHLIGHT_TEXT = 1
+COLOR_HIGHLIGHT_NICK = 45
# User list color
COLOR_USER_VISITOR = 7
diff --git a/src/core.py b/src/core.py
index e2b2fb1e..46e10793 100644
--- a/src/core.py
+++ b/src/core.py
@@ -887,7 +887,7 @@ class Core(object):
self.refresh_window()
self.doupdate()
- def add_message_to_text_buffer(self, room, txt, time=None, nickname=None, colorized=False):
+ def add_message_to_text_buffer(self, room, txt, time=None, nickname=None):
"""
Add the message to the room if possible, else, add it to the Info window
(in the Info tab of the info window in the RosterTab)
@@ -895,7 +895,7 @@ class Core(object):
if not room:
self.information('Error, trying to add a message in no room: %s' % txt)
else:
- room.add_message(txt, time, nickname, colorized)
+ room.add_message(txt, time, nickname)
self.refresh_window()
def command_help(self, arg):
diff --git a/src/room.py b/src/room.py
index 4196ce5f..d062e29c 100644
--- a/src/room.py
+++ b/src/room.py
@@ -55,19 +55,19 @@ class Room(TextBuffer):
def do_highlight(self, txt, time, nickname):
"""
- Set the tab color and returns the txt color
+ Set the tab color and returns the nick color
"""
- color = theme.COLOR_NORMAL_TEXT
+ color = None
if not time and nickname and nickname != self.own_nick and self.joined:
if self.own_nick.lower() in txt.lower():
self.set_color_state(theme.COLOR_TAB_HIGHLIGHT)
- color = theme.COLOR_HIGHLIGHT_TEXT
+ color = theme.COLOR_HIGHLIGHT_NICK
else:
highlight_words = config.get('highlight_on', '').split(':')
for word in highlight_words:
if word and word.lower() in txt.lower():
self.set_color_state(theme.COLOR_TAB_HIGHLIGHT)
- color = theme.COLOR_HIGHLIGHT_TEXT
+ color = theme.COLOR_HIGHLIGHT_NICK
break
return color
@@ -84,7 +84,7 @@ class Room(TextBuffer):
"""
self.color_state = color
- def add_message(self, txt, time=None, nickname=None, colorized=False, forced_user=None, nick_color=None):
+ def add_message(self, txt, time=None, nickname=None, forced_user=None, nick_color=None):
"""
Note that user can be None even if nickname is not None. It happens
when we receive an history message said by someone who is not
@@ -92,29 +92,28 @@ class Room(TextBuffer):
"""
self.log_message(txt, time, nickname)
if txt.startswith('/me '):
- txt = "* " + nickname + ' ' + txt[4:]
+ txt = "\x192* \x195" + nickname + ' ' + txt[4:]
nickname = None
user = self.get_user_by_name(nickname) if nickname is not None else None
if user:
user.set_last_talked(datetime.now())
if not user and forced_user:
user = forced_user
- color = theme.COLOR_NORMAL_TEXT
if not time and nickname and\
nickname != self.own_nick and\
self.color_state != theme.COLOR_TAB_CURRENT:
if self.color_state != theme.COLOR_TAB_HIGHLIGHT:
self.set_color_state(theme.COLOR_TAB_NEW_MESSAGE)
- if not nickname:
- color = theme.COLOR_INFORMATION_TEXT
- else:
- color = self.do_highlight(txt, time, nickname)
- if time: # History messages are colored to be distinguished
- color = theme.COLOR_INFORMATION_TEXT
- time = time or datetime.now()
nick_color = nick_color or user.color if user else None
- message = Message(txt=txt, colorized=colorized, nick_color=nick_color,
- time=time, nickname=nickname, color=color, user=user)
+ if not nickname or time:
+ txt = '\x195%s' % (txt,)
+ else: # TODO
+ highlight = self.do_highlight(txt, time, nickname)
+ if highlight:
+ nick_color = highlight
+ time = time or datetime.now()
+ message = Message(txt=txt, nick_color=nick_color,
+ time=time, nickname=nickname, user=user)
# message = Message(txt, time, nickname, nick_color, color, colorized, user=user)
while len(self.messages) > self.messages_nb_limit:
self.messages.pop(0)
diff --git a/src/tabs.py b/src/tabs.py
index f6b833a7..ccafe881 100644
--- a/src/tabs.py
+++ b/src/tabs.py
@@ -727,11 +727,9 @@ class MucTab(ChatTab):
if from_nick == room.own_nick:
room.joined = True
new_user.color = theme.COLOR_OWN_NICK
- # self.add_message_to_text_buffer(room, _("Your nickname is %s") % (from_nick))
- room.add_message(_("Your nickname is %s") % (from_nick))
+ room.add_message(_("\x195Your nickname is %s") % (from_nick))
if '170' in status_codes:
- # self.add_message_to_text_buffer(room, 'Warning: this room is publicly logged')
- room.add_message('Warning: this room is publicly logged')
+ room.add_message('\x195Warning: this room is publicly logged')
else:
change_nick = '303' in status_codes
kick = '307' in status_codes and typ == 'unavailable'
@@ -766,9 +764,9 @@ class MucTab(ChatTab):
hide_exit_join = config.get('hide_exit_join', -1)
if hide_exit_join != 0:
if not jid.full:
- room.add_message(_('%(spec)s "[%(nick)s]" joined the room') % {'nick':from_nick.replace('"', '\\"'), 'spec':theme.CHAR_JOIN.replace('"', '\\"')}, colorized=True)
+ room.add_message('\x194%(spec)s \x193%(nick)s\x195 joined the room' % {'nick':from_nick, 'spec':theme.CHAR_JOIN})
else:
- room.add_message(_('%(spec)s "[%(nick)s]" "(%(jid)s)" joined the room') % {'spec':theme.CHAR_JOIN.replace('"', '\\"'), 'nick':from_nick.replace('"', '\\"'), 'jid':jid.full}, colorized=True)
+ room.add_message('\x194%(spec)s \x193%(nick)s (\x196%(jid)s\x195 joined the room' % {'spec':theme.CHAR_JOIN, 'nick':from_nick, 'jid':jid.full})
def on_user_nick_change(self, room, presence, user, from_nick, from_room):
new_nick = presence.find('{http://jabber.org/protocol/muc#user}x/{http://jabber.org/protocol/muc#user}item').attrib['nick']
@@ -779,7 +777,7 @@ class MucTab(ChatTab):
if isinstance(_tab, PrivateTab) and JID(_tab.get_name()).bare == room.name:
_tab.get_room().own_nick = new_nick
user.change_nick(new_nick)
- room.add_message(_('"[%(old)s]" is now known as "[%(new)s]"') % {'old':from_nick.replace('"', '\\"'), 'new':new_nick.replace('"', '\\"')}, colorized=True)
+ room.add_message('\x193%(old)s\x195 is now known as \x193%(new)s' % {'old':from_nick, 'new':new_nick})
# rename the private tabs if needed
self.core.rename_private_tabs(room.name, from_nick, new_nick)
@@ -794,16 +792,16 @@ class MucTab(ChatTab):
if from_nick == room.own_nick: # we are banned
room.disconnect()
if by:
- kick_msg = _('%(spec)s [You] have been banned by "[%(by)s]"') % {'spec': theme.CHAR_KICK.replace('"', '\\"'), 'by':by}
+ kick_msg = _('\x191%(spec)s \x193You\x195 have been banned by \x194%(by)s') % {'spec': theme.CHAR_KICK, 'by':by}
else:
- kick_msg = _('%(spec)s [You] have been banned.') % {'spec':theme.CHAR_KICK.replace('"', '\\"')}
+ kick_msg = _('\x191%(spec)s \x193You\x195 have been banned.') % {'spec':theme.CHAR_KICK}
else:
if by:
- kick_msg = _('%(spec)s "[%(nick)s]" has been banned by "[%(by)s]"') % {'spec':theme.CHAR_KICK.replace('"', '\\"'), 'nick':from_nick.replace('"', '\\"'), 'by':by.replace('"', '\\"')}
+ kick_msg = _('\x191%(spec)s \x193%(nick)s\x195 has been banned by \x194%(by)s') % {'spec':theme.CHAR_KICK, 'nick':from_nick, 'by':by}
else:
- kick_msg = _('%(spec)s "[%(nick)s]" has been banned') % {'spec':theme.CHAR_KICK, 'nick':from_nick.replace('"', '\\"')}
+ kick_msg = _('\x191%(spec)s \x193%(nick)s \x195has been banned') % {'spec':theme.CHAR_KICK, 'nick':from_nick.replace('"', '\\"')}
if reason is not None and reason.text:
- kick_msg += _(' Reason: %(reason)s') % {'reason': reason.text}
+ kick_msg += _(' Reason: \x196%(reason)s') % {'reason': reason.text}
room.add_message(kick_msg, colorized=True)
def on_user_kicked(self, room, presence, user, from_nick):
@@ -817,20 +815,20 @@ class MucTab(ChatTab):
if from_nick == room.own_nick: # we are kicked
room.disconnect()
if by:
- kick_msg = _('%(spec)s [You] have been kicked by "[%(by)s]"') % {'spec': theme.CHAR_KICK.replace('"', '\\"'), 'by':by}
+ kick_msg = _('\x191%(spec)s \x193You \x195have been kicked by \x194%(by)s') % {'spec': theme.CHAR_KICK, 'by':by}
else:
- kick_msg = _('%(spec)s [You] have been kicked.') % {'spec':theme.CHAR_KICK.replace('"', '\\"')}
+ kick_msg = _('\x191%(spec)s \x193You \x195have been kicked.') % {'spec':theme.CHAR_KICK}
# try to auto-rejoin
if config.get('autorejoin', 'false') == 'true':
- muc.join_groupchat(self.xmpp, room.name, room.own_nick)
+ muc.join_groupchat(self.core.xmpp, room.name, room.own_nick)
else:
if by:
kick_msg = _('%(spec)s "[%(nick)s]" has been kicked by "[%(by)s]"') % {'spec':theme.CHAR_KICK.replace('"', '\\"'), 'nick':from_nick.replace('"', '\\"'), 'by':by.replace('"', '\\"')}
else:
kick_msg = _('%(spec)s "[%(nick)s]" has been kicked') % {'spec':theme.CHAR_KICK, 'nick':from_nick.replace('"', '\\"')}
if reason is not None and reason.text:
- kick_msg += _(' Reason: %(reason)s') % {'reason': reason.text}
- room.add_message(kick_msg, colorized=True)
+ kick_msg += _(' Reason: (\x196%reason\x195)s') % {'reason': reason.text}
+ room.add_message(kick_msg)
def on_user_leave_groupchat(self, room, user, jid, status, from_nick, from_room):
"""
@@ -843,12 +841,12 @@ class MucTab(ChatTab):
hide_exit_join = config.get('hide_exit_join', -1) if config.get('hide_exit_join', -1) >= -1 else -1
if hide_exit_join == -1 or user.has_talked_since(hide_exit_join):
if not jid.full:
- leave_msg = _('%(spec)s "[%(nick)s]" has left the room') % {'nick':from_nick.replace('"', '\\"'), 'spec':theme.CHAR_QUIT.replace('"', '\\"')}
+ leave_msg = _('\x191%(spec)s \x193%(nick)s \x195has left the room') % {'nick':from_nick, 'spec':theme.CHAR_QUIT}
else:
- leave_msg = _('%(spec)s "[%(nick)s]" "(%(jid)s)" has left the room') % {'spec':theme.CHAR_QUIT.replace('"', '\\"'), 'nick':from_nick.replace('"', '\\"'), 'jid':jid.full.replace('"', '\\"')}
+ leave_msg = _('\x191%(spec)s \x193%(nick)s (\x194%(jid)s) \x195has left the room') % {'spec':theme.CHAR_QUIT, 'nick':from_nick, 'jid':jid.full}
if status:
leave_msg += ' (%s)' % status
- room.add_message(leave_msg, colorized=True)
+ room.add_message(leave_msg)
self.core.on_user_left_private_conversation(from_room, from_nick, status)
def on_user_change_status(self, room, user, from_nick, from_room, affiliation, role, show, status):
@@ -858,7 +856,7 @@ class MucTab(ChatTab):
# build the message
display_message = False # flag to know if something significant enough
# to be displayed has changed
- msg = _('"%s" changed: ')% from_nick.replace('"', '\\"')
+ msg = _('\x193%s \x195changed: ')% from_nick.replace('"', '\\"')
if affiliation != user.affiliation:
msg += _('affiliation: %s, ') % affiliation
display_message = True
diff --git a/src/text_buffer.py b/src/text_buffer.py
index 65da6975..1c112222 100644
--- a/src/text_buffer.py
+++ b/src/text_buffer.py
@@ -27,7 +27,7 @@ from datetime import datetime
import theme
from config import config
-Message = collections.namedtuple('Message', 'txt colorized nick_color time nickname color user')
+Message = collections.namedtuple('Message', 'txt nick_color time nickname user')
class TextBuffer(object):
"""
@@ -44,11 +44,12 @@ class TextBuffer(object):
def add_window(self, win):
self.windows.append(win)
- def add_message(self, txt, time=None, nickname=None, colorized=False, nick_color=None):
- color = theme.COLOR_NORMAL_TEXT if nickname is not None else theme.COLOR_INFORMATION_TEXT
+ def add_message(self, txt, time=None, nickname=None, nick_color=None):
+ if not nickname:
+ txt = '\x195%s' % (txt,)
nick_color = nick_color
- msg = Message(txt=txt, colorized=colorized, nick_color=nick_color,
- time=time or datetime.now(), nickname=nickname, color=color, user=None)
+ msg = Message(txt=txt, nick_color=nick_color,
+ time=time or datetime.now(), nickname=nickname, user=None)
self.messages.append(msg)
while len(self.messages) > self.messages_nb_limit:
self.messages.pop(0)
diff --git a/src/theme.py b/src/theme.py
index 42bc3aed..e5d10f84 100644
--- a/src/theme.py
+++ b/src/theme.py
@@ -34,7 +34,7 @@ log = logging.getLogger(__name__)
# Message text color
COLOR_NORMAL_TEXT = 0
COLOR_INFORMATION_TEXT = 5
-COLOR_HIGHLIGHT_TEXT = 1
+COLOR_HIGHLIGHT_NICK = 45
# User list color
COLOR_USER_VISITOR = 7
diff --git a/src/wcwidth.py b/src/wcwidth.py
index bb0c456e..d44464b4 100644
--- a/src/wcwidth.py
+++ b/src/wcwidth.py
@@ -186,9 +186,17 @@ def wcwidth(ucs):
if ucs == '\u0000':
return 0
+ # special case for \x19
+ if ucs == '\x19':
+ # -1 is not an error, that’s the real size that
+ # should be counted, because if a \x19 is found,
+ # the next char should not be counted
+ # So '\x19' and 'a' is -1 + 1 = 0
+ return -1
+
# non-printable chars.
if ucs < '\u0020' or (ucs >= '\u007f' and ucs < '\u00a0'):
- return -1
+ return -2
# binary search in table of non-spacing characters
if bisearch(ucs):
@@ -225,7 +233,7 @@ def wcswidth(s):
width = 0
for c in s:
w = wcwidth(c)
- if w < 0:
+ if w < -1:
# If s contains a non-printable char, we should return -1.
# This includes newlines and tabs!
return -1
@@ -241,8 +249,8 @@ def wcsislonger(s, l):
width = 0
for c in s:
w = wcwidth(c)
- if w < 0:
- return -1
+ if w < -1:
+ return True
else:
width += w
if width > l:
@@ -258,7 +266,7 @@ def widthcut(s, m):
width = 0
for c in s:
w = wcwidth(c)
- if w < 0:
+ if w < -1:
return None
else:
width += w
diff --git a/src/windows.py b/src/windows.py
index 4300b240..0bad8c26 100644
--- a/src/windows.py
+++ b/src/windows.py
@@ -50,7 +50,7 @@ import wcwidth
import singleton
import collections
-Line = collections.namedtuple('Line', 'text colorized text_offset text_color nickname_color time nickname')
+Line = collections.namedtuple('Line', 'text text_offset nickname_color time nickname')
g_lock = Lock()
@@ -98,6 +98,38 @@ class Win(object):
except:
pass
+ def addstr_colored(self, string, y=None, x=None):
+ """
+ Write a string on the window, setting the
+ attributes as they are in the string.
+ For example:
+ \x19bhello → hello in bold
+ \xc1Bonj\xc2our → 'Bonj' in red and 'our' in green
+ next_attr_char is the \x19 delimiter
+ attr_char is the char following it, it can be
+ one of 'u', 'b', 'c[0-9]'
+ """
+ if y is not None and x is not None:
+ self._win.move(y, x)
+ next_attr_char = string.find('\x19')
+ self._win.attrset(0) # reset all attr
+ while next_attr_char != -1:
+ attr_char = string[next_attr_char+1].lower()
+ if next_attr_char != 0:
+ self.addstr(string[:next_attr_char])
+ string = string[next_attr_char+2:]
+ if attr_char == 'o':
+ self._win.attrset(0)
+ elif attr_char == 'u':
+ self._win.attron(curses.A_UNDERLINE)
+ elif attr_char == 'b':
+ self._win.attron(curses.A_BOLD)
+ elif attr_char.isdigit():
+ self._win.attron(common.curses_color_pair(int(attr_char)))
+ next_attr_char = string.find('\x19')
+ self.addstr(string)
+ self._win.attrset(0)
+
def finish_line(self, color):
"""
Write colored spaces until the end of line
@@ -546,8 +578,8 @@ class TextWin(Win):
else:
time = None
nickname = None
- self.built_lines.append(Line(text=cutted_txt, colorized=message.colorized,
- text_offset=offset, text_color=message.color,
+ self.built_lines.append(Line(text=cutted_txt,
+ text_offset=offset,
nickname_color=color, time=time,
nickname=nickname))
nb += 1
@@ -576,7 +608,7 @@ class TextWin(Win):
else:
self.write_time(line.time)
self.write_nickname(line.nickname, line.nickname_color)
- self.write_text(y, line.text_offset, line.text, line.text_color, line.colorized)
+ self.write_text(y, line.text_offset, line.text)
if y != self.height-1:
self.addstr('\n')
self._refresh()
@@ -584,10 +616,12 @@ class TextWin(Win):
def write_line_separator(self):
self.addnstr('- '*(self.width//2-1)+'-', self.width, common.curses_color_pair(theme.COLOR_NEW_TEXT_SEPARATOR))
- def write_text(self, y, x, txt, color, colorized):
+ def write_text(self, y, x, txt):
"""
write the text of a line.
"""
+ self.addstr_colored(txt, y, x)
+ return
if not colorized:
if color:
self._win.attron(common.curses_color_pair(color))