Some optimizations in build_new_message. Also cleaned up. Added an optimized way to do "wcswidth(string) > n": wcsislonger. And should use less memory because the dict replacing Message and Lines object stores ONLY the needed attributes.
This commit is contained in:
parent
1a2252b3e5
commit
a516e78bcf
6 changed files with 79 additions and 150 deletions
|
@ -1,85 +0,0 @@
|
|||
# Copyright 2010-2011 Le Coz Florent <louiz@louiz.org>
|
||||
#
|
||||
# This file is part of Poezio.
|
||||
#
|
||||
# Poezio is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Poezio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Poezio. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
Define the Message class
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
class Message(object):
|
||||
"""
|
||||
A message with all the associated data (nickname, time, color, etc)
|
||||
The color can be a single number OR a list of numbers, for
|
||||
specials cases like join or quit messages.
|
||||
"""
|
||||
def __init__(self, txt, time=None, nickname=None, nick_color=None, color=None, colorized=False, user=None):
|
||||
"""
|
||||
time is a datetime object, None means 'now'.
|
||||
If no nickname is specified, it's an information.
|
||||
"""
|
||||
self.txt = txt
|
||||
self.nickname = nickname
|
||||
self.time = time
|
||||
self.nick_color = nick_color
|
||||
self.color = color
|
||||
self.colorized = colorized
|
||||
self.user = user
|
||||
|
||||
def __repr__(self):
|
||||
return "<Message txt=%s, nickname=%s, time=%s, user=%s, colorized=%s>" % (self.txt, self.nickname, str(self.time), str(self.user), self.colorized)
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
class Line(object):
|
||||
"""
|
||||
A line, corresponding to ONE row of a TextWin.
|
||||
A message is composed of ONE line or MORE.
|
||||
The same particularity for colors in Message class applies
|
||||
here too.
|
||||
Example:
|
||||
|
||||
Text area limit text area limit
|
||||
v v
|
||||
|[12:12:01] nickone has just joined the room named |
|
||||
| test@kikoo.louiz.org |
|
||||
|[12:12:23] nickone> hello good morning everyone, I am|
|
||||
| seeking for informations about |
|
||||
| poezio |
|
||||
|[12:12:35] secondnick> Hello nickone, you can get |
|
||||
| informations here :\n |
|
||||
| http://blablablabla |
|
||||
|
||||
To get this result, the three messages should be converted to:
|
||||
|
||||
Line(None, None, Datetime(12, 12, 01), "nickone has just joined the room named", 0, 10)
|
||||
Line(None, None, None, "test@kikoo.louiz.org", 0, 10)
|
||||
Line("nickone", 1, Datetime(12, 12, 23), "hello good morning everyone, I am", 0, 20)
|
||||
Line(None, None, None, "seeking for informations about", 0, 20)
|
||||
Line(None, None, None, "poezio", 0, 20)
|
||||
Line("secondnick", 2, Datetime(12, 12, 35), "Hello nickone, you can get", 0, 23)
|
||||
Line(None, None, None, "informations here:", 0, 23)
|
||||
Line(None, None, None, "http://blablablabla", 0, 23)
|
||||
"""
|
||||
def __init__(self, nickname, nickname_color, time, text, text_color, text_offset, colorized=False):
|
||||
self.nickname = nickname
|
||||
self.nickname_color = nickname_color
|
||||
self.time = time
|
||||
self.text = text
|
||||
self.text_color = text_color
|
||||
self.text_offset = text_offset
|
||||
self.colorized = colorized
|
13
src/room.py
13
src/room.py
|
@ -19,7 +19,6 @@ from datetime import datetime
|
|||
from random import randrange
|
||||
from config import config
|
||||
from logger import logger
|
||||
from message import Message
|
||||
|
||||
import common
|
||||
import theme
|
||||
|
@ -114,7 +113,17 @@ class Room(TextBuffer):
|
|||
color = theme.COLOR_INFORMATION_TEXT
|
||||
time = time if time is not None else datetime.now()
|
||||
nick_color = nick_color or user.color if user else None
|
||||
message = Message(txt, time, nickname, nick_color, color, colorized, user=user)
|
||||
message = {'txt': txt, 'colorized':colorized,
|
||||
'time':time}
|
||||
if nickname:
|
||||
message['nickname'] = nickname
|
||||
if nick_color:
|
||||
message['nick_color'] = nick_color
|
||||
if color:
|
||||
message['color'] = color
|
||||
if user:
|
||||
message['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)
|
||||
self.messages.append(message)
|
||||
|
|
|
@ -781,7 +781,7 @@ class MucTab(ChatTab):
|
|||
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)
|
||||
# rename the private tabs if needed
|
||||
self.core.rename_private_tab(room.name, from_nick, new_nick)
|
||||
self.core.rename_private_tabs(room.name, from_nick, new_nick)
|
||||
|
||||
def on_user_banned(self, room, presence, user, from_nick):
|
||||
"""
|
||||
|
|
|
@ -21,7 +21,6 @@ Define the TextBuffer class
|
|||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
from message import Message
|
||||
from datetime import datetime
|
||||
import theme
|
||||
from config import config
|
||||
|
@ -44,8 +43,14 @@ class TextBuffer(object):
|
|||
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
|
||||
nick_color = nick_color
|
||||
time = time or datetime.now()
|
||||
msg = Message(txt, time, nickname, nick_color, color, colorized)
|
||||
msg = {'txt': txt, 'colorized':colorized,
|
||||
'time':time or datetime.now()}
|
||||
if nickname:
|
||||
message['nickname'] = nickname
|
||||
if nick_color:
|
||||
message['nick_color'] = nick_color
|
||||
if color:
|
||||
message['color'] = color
|
||||
self.messages.append(msg)
|
||||
while len(self.messages) > self.messages_nb_limit:
|
||||
self.messages.pop(0)
|
||||
|
|
|
@ -233,6 +233,22 @@ def wcswidth(s):
|
|||
width += w
|
||||
return width
|
||||
|
||||
def wcsislonger(s, l):
|
||||
"""
|
||||
Returns the same result than "wcswidth(s) > l" but
|
||||
is faster.
|
||||
"""
|
||||
width = 0
|
||||
for c in s:
|
||||
w = wcwidth(c)
|
||||
if w < 0:
|
||||
return -1
|
||||
else:
|
||||
width += w
|
||||
if width > l:
|
||||
return True
|
||||
return False
|
||||
|
||||
def widthcut(s, m):
|
||||
"""
|
||||
Return the first characters of s that can be contained in
|
||||
|
|
100
src/windows.py
100
src/windows.py
|
@ -38,7 +38,7 @@ from threading import Lock
|
|||
from contact import Contact, Resource
|
||||
from roster import RosterGroup, roster
|
||||
|
||||
from message import Line
|
||||
# from message import Line
|
||||
from tabs import MIN_WIDTH, MIN_HEIGHT
|
||||
|
||||
from sleekxmpp.xmlstream.stanzabase import JID
|
||||
|
@ -495,67 +495,57 @@ class TextWin(Win):
|
|||
Return the number of lines that are built for the given
|
||||
message.
|
||||
"""
|
||||
if message == None: # line separator
|
||||
def cut_text(text, width):
|
||||
"""
|
||||
returns the text that should be displayed on the line, and the rest
|
||||
of the text, in a tuple
|
||||
"""
|
||||
cutted = wcwidth.widthcut(text, width) or text[:width]
|
||||
limit = cutted.find('\n')
|
||||
if limit >= 0:
|
||||
return (text[limit+1:], text[:limit])
|
||||
if not wcwidth.wcsislonger(text, width):
|
||||
return ('', text)
|
||||
limit = cutted.rfind(' ')
|
||||
if limit <= 0:
|
||||
return (text[len(cutted):], cutted)
|
||||
else:
|
||||
return (text[limit+1:], text[:limit])
|
||||
|
||||
if message is None: # line separator
|
||||
self.built_lines.append(None)
|
||||
return 0
|
||||
txt = message.txt
|
||||
txt = message.get('txt')
|
||||
if not txt:
|
||||
return 0
|
||||
else:
|
||||
txt = txt.replace('\t', ' ')
|
||||
# length of the time
|
||||
offset = 9+len(theme.CHAR_TIME_LEFT[:1])+len(theme.CHAR_TIME_RIGHT[:1])
|
||||
if message.nickname and wcwidth.wcswidth(message.nickname) >= 25:
|
||||
nick = message.nickname[:25]+'…'
|
||||
nickname = message.get('nickname')
|
||||
if nickname and len(nickname) >= 25:
|
||||
nick = nickname[:25]+'…'
|
||||
else:
|
||||
nick = message.nickname
|
||||
nick = nickname
|
||||
if nick:
|
||||
offset += wcwidth.wcswidth(nick) + 2 # + nick + spaces length
|
||||
first = True
|
||||
this_line_was_broken_by_space = False
|
||||
nb = 0
|
||||
while txt != '':
|
||||
cutted_txt = wcwidth.widthcut(txt, self.width-offset) or txt[:self.width-offset]
|
||||
limit = cutted_txt.find('\n')
|
||||
if limit < 0:
|
||||
# break between words if possible
|
||||
if wcwidth.wcswidth(txt) >= self.width-offset:
|
||||
cutted_txt = wcwidth.widthcut(txt, self.width-offset) or txt[:self.width-offset]
|
||||
limit = cutted_txt.rfind(' ')
|
||||
this_line_was_broken_by_space = True
|
||||
if limit <= 0:
|
||||
limit = self.width-offset
|
||||
this_line_was_broken_by_space = False
|
||||
else:
|
||||
limit = self.width-offset-1
|
||||
this_line_was_broken_by_space = False
|
||||
color = message.user.color if message.user else message.nick_color
|
||||
if not first:
|
||||
nick = None
|
||||
time = None
|
||||
else: # strftime is VERY slow, improve performance
|
||||
# by calling it only one time here, and
|
||||
# not at each refresh
|
||||
time = {'hour': '%s'%(message.time.strftime("%H"),),
|
||||
'minute': '%s'%(message.time.strftime("%M"),),
|
||||
'second': '%s'%(message.time.strftime("%S"),),
|
||||
(txt, cutted_txt) = cut_text(txt, self.width-offset)
|
||||
l = {'colorized': message.get('colorized'),
|
||||
'text_offset':offset,
|
||||
'text_color':message.get('color'),
|
||||
'text': cutted_txt
|
||||
}
|
||||
l = Line(nick, color,
|
||||
time,
|
||||
wcwidth.widthcut(txt, limit) or txt[:limit], message.color,
|
||||
offset,
|
||||
message.colorized)
|
||||
color = message.get('user').color if message.get('user') else message.get('nick_color')
|
||||
if first and color:
|
||||
l['nickname_color'] = color
|
||||
if first:
|
||||
l['time'] = message.get('time').strftime("%H:%M:%S")
|
||||
l['nickname'] = nick
|
||||
self.built_lines.append(l)
|
||||
nb += 1
|
||||
if this_line_was_broken_by_space:
|
||||
limit += 1 # jump the space at the start of the line
|
||||
cutted_txt = wcwidth.widthcut(txt, limit)
|
||||
if not cutted_txt:
|
||||
txt = txt[limit:]
|
||||
else:
|
||||
txt = txt[len(cutted_txt):]
|
||||
if txt.startswith('\n'):
|
||||
txt = txt[1:]
|
||||
first = False
|
||||
while len(self.built_lines) > self.lines_nb_limit:
|
||||
self.built_lines.pop(0)
|
||||
|
@ -579,12 +569,12 @@ class TextWin(Win):
|
|||
if line is None:
|
||||
self.write_line_separator()
|
||||
else:
|
||||
if line.time:
|
||||
self.write_time(line.time)
|
||||
if line.nickname:
|
||||
self.write_nickname(line.nickname, line.nickname_color)
|
||||
self.write_text(y, line.text_offset, line.text, line.text_color, line.colorized)
|
||||
if y != self.height-1 or (not line or line.text_offset+wcwidth.wcswidth(line.text) < self.width):
|
||||
if line.get('time'):
|
||||
self.write_time(line.get('time'))
|
||||
if line.get('nickname'):
|
||||
self.write_nickname(line.get('nickname'), line.get('nickname_color'))
|
||||
self.write_text(y, line.get('text_offset'), line.get('text'), line.get('text_color'), line.get('colorized'))
|
||||
if y != self.height-1 or (not line or line.get('text_offset')+wcwidth.wcswidth(line.get('text')) < self.width):
|
||||
self.addstr('\n')
|
||||
self._refresh()
|
||||
|
||||
|
@ -648,13 +638,7 @@ class TextWin(Win):
|
|||
"""
|
||||
Write the date on the yth line of the window
|
||||
"""
|
||||
self.addstr(theme.CHAR_TIME_LEFT, common.curses_color_pair(theme.COLOR_TIME_LIMITER))
|
||||
self.addstr(time['hour'], common.curses_color_pair(theme.COLOR_TIME_NUMBERS))
|
||||
self.addstr(':', common.curses_color_pair(theme.COLOR_TIME_SEPARATOR))
|
||||
self.addstr(time['minute'], common.curses_color_pair(theme.COLOR_TIME_NUMBERS))
|
||||
self.addstr(':', common.curses_color_pair(theme.COLOR_TIME_SEPARATOR))
|
||||
self.addstr(time['second'], common.curses_color_pair(theme.COLOR_TIME_NUMBERS))
|
||||
self.addstr(theme.CHAR_TIME_RIGHT, common.curses_color_pair(theme.COLOR_TIME_LIMITER))
|
||||
self.addstr(time)
|
||||
self.addstr(' ')
|
||||
|
||||
def resize(self, height, width, y, x, room=None):
|
||||
|
|
Loading…
Reference in a new issue