From 2e04c5c77e64a45e9ab8a23b8cb7a683630eb067 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 8 Sep 2011 17:05:02 +0200 Subject: =?UTF-8?q?c=20code=20that=20doesn=E2=80=99t=20work?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 2 + src/pooptmodule.c | 277 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/room.py | 17 +--- src/text_buffer.py | 9 +- src/windows.py | 96 +++++++------------ 5 files changed, 322 insertions(+), 79 deletions(-) create mode 100644 src/pooptmodule.c diff --git a/Makefile b/Makefile index a327413a..8c0935f0 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,8 @@ LOCALEDIR=$(DATADIR)/locale MANDIR=$(DATADIR)/man all: Makefile + python3 setup.py build + cp build/lib.linux-x86_64-3.2/poopt.cpython-32mu.so src/ clean: find ./ -name \*.pyc -delete diff --git a/src/pooptmodule.c b/src/pooptmodule.c new file mode 100644 index 00000000..cdc0d127 --- /dev/null +++ b/src/pooptmodule.c @@ -0,0 +1,277 @@ +/* Copyright 2010-2011 Florent Le Coz */ + +/* This file is part of Poezio. */ + +/* Poezio is free software: you can redistribute it and/or modify */ +/* it under the terms of the MIT license. See the COPYING file. */ + +/** The poopt python3 module +**/ + +/* This file is a python3 module for poezio, used to replace some time-critical +python functions that are too slow. If compiled, poezio will use this module, +otherwise it will just use the equivalent python functions. */ + +#define PY_SSIZE_T_CLEAN + +#include "Python.h" + +PyObject *ErrorObject; +#define DEBUG(...) fprintf(stderr, __VA_ARGS__) + +/*** + The module functions + ***/ + +/* cut_text: takes a string and returns a tuple of int. + Each two int tuple is a line, represented by the ending position it (where it should be cut). + Not that this position is calculed using the position of the python string characters, + not just the individual bytes. + For example, poopt_cut_text("vivent les frigidaires", 6); + will return [(0, 6), (7, 10), (11, 17), (17, 22)], meaning that the lines are + "vivent", "les", "frigid" and "aires" +*/ +PyDoc_STRVAR(poopt_cut_text_doc, "cut_text(width, text)\n\n\nReturn the list of strings, cut according to the given size."); + +static PyObject *poopt_cut_text(PyObject *self, PyObject *args) +{ + int length; + unsigned char *buffer; + int width; + + if (PyArg_ParseTuple(args, "es#i", NULL, &buffer, &length, &width) == 0) + return NULL; + + int bpos = 0; /* the real position in the char* */ + int spos = 0; /* the position, considering UTF-8 chars */ + int last_space = -1; + int start_pos = 0; + + PyObject* retlist = PyList_New(0); + + while (bpos < length) + { + if (buffer[bpos] == ' ') + last_space = spos; + else if (buffer[bpos] == '\n') + { + if (PyList_Append(retlist, Py_BuildValue("ii", start_pos, spos)) == -1) + return NULL; + start_pos = spos + 1; + last_space = -1; + } + else if ((spos - start_pos) >= width) + { + if (last_space == -1) + { + if (PyList_Append(retlist, Py_BuildValue("ii", start_pos, spos)) == -1) + return NULL; + start_pos = spos; + } + else + { + if (PyList_Append(retlist, Py_BuildValue("ii", start_pos, last_space)) == -1) + return NULL; + start_pos = last_space + 1; + last_space = -1; + } + } + if (buffer[bpos] == 25) /* \x19 */ + { + spos--; + bpos += 1; + } + else if (buffer[bpos] <= 127) /* ASCII char on one byte */ + bpos += 1; + else if (buffer[bpos] <= 195) + bpos += 2; + else if (buffer[bpos] <= 225) + bpos += 3; + else + bpos += 4; + spos++; + } + if (PyList_Append(retlist, Py_BuildValue("(i,i)", start_pos, spos)) == -1) + return NULL; + return retlist; +} + +/*** + Module initialization. Just taken from the xxmodule.c template from the python sources. + ***/ +static PyTypeObject Str_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "pooptmodule.Str", /*tp_name*/ + 0, /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_reserved*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /* see PyInit_xx */ /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + 0, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + +/* ---------- */ + +static PyObject * +null_richcompare(PyObject *self, PyObject *other, int op) +{ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + +static PyTypeObject Null_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "pooptmodule.Null", /*tp_name*/ + 0, /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_reserved*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + null_richcompare, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /* see PyInit_xx */ /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + 0, /* see PyInit_xx */ /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + + +/* List of functions defined in the module */ + +static PyMethodDef poopt_methods[] = { + {"cut_text", poopt_cut_text, METH_VARARGS, + poopt_cut_text_doc}, + {NULL, NULL} /* sentinel */ +}; + +PyDoc_STRVAR(module_doc, + "This is a template module just for instruction. And poopt."); + +/* Initialization function for the module (*must* be called PyInit_xx) */ + +static struct PyModuleDef pooptmodule = { + PyModuleDef_HEAD_INIT, + "poopt", + module_doc, + -1, + poopt_methods, + NULL, + NULL, + NULL, + NULL +}; + +PyMODINIT_FUNC +PyInit_poopt(void) +{ + PyObject *m = NULL; + + /* Due to cross platform compiler issues the slots must be filled + * here. It's required for portability to Windows without requiring + * C++. */ + Null_Type.tp_base = &PyBaseObject_Type; + Null_Type.tp_new = PyType_GenericNew; + Str_Type.tp_base = &PyUnicode_Type; + + /* Finalize the type object including setting type of the new type + * object; doing it here is required for portability, too. */ + /* if (PyType_Ready(&Xxo_Type) < 0) */ + /* goto fail; */ + + /* Create the module and add the functions */ + m = PyModule_Create(&pooptmodule); + if (m == NULL) + goto fail; + + /* Add some symbolic constants to the module */ + if (ErrorObject == NULL) { + ErrorObject = PyErr_NewException("poopt.error", NULL, NULL); + if (ErrorObject == NULL) + goto fail; + } + Py_INCREF(ErrorObject); + PyModule_AddObject(m, "error", ErrorObject); + + /* Add Str */ + if (PyType_Ready(&Str_Type) < 0) + goto fail; + PyModule_AddObject(m, "Str", (PyObject *)&Str_Type); + + /* Add Null */ + if (PyType_Ready(&Null_Type) < 0) + goto fail; + PyModule_AddObject(m, "Null", (PyObject *)&Null_Type); + return m; + fail: + Py_XDECREF(m); + return NULL; +} + +/* /\* test function *\/ */ +/* int main(void) */ +/* { */ +/* char coucou[] = "vive le foutre, le beurre et le caca boudin"; */ + +/* cut_text(coucou, 8); */ +/* } */ diff --git a/src/room.py b/src/room.py index 5d4c4ce6..1ca3f599 100644 --- a/src/room.py +++ b/src/room.py @@ -1,18 +1,9 @@ -# Copyright 2010-2011 Le Coz Florent +# Copyright 2010-2011 Florent Le Coz # # 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 . +# it under the terms of the MIT license. See the COPYING file. from text_buffer import TextBuffer, Message from datetime import datetime @@ -129,7 +120,9 @@ class Room(TextBuffer): nick_color = highlight time = time or datetime.now() message = Message(txt='%s\x19o'%(txt,), nick_color=nick_color, - time=time, nickname=nickname, user=user) + time=time, str_time=time.strftime("%Y-%m-%d %H:%M:%S")\ + if history else time.strftime("%H:%M:%S"),\ + nickname=nickname, user=user) while len(self.messages) > self.messages_nb_limit: self.messages.pop(0) self.messages.append(message) diff --git a/src/text_buffer.py b/src/text_buffer.py index a3b5b1fb..77646aea 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 nick_color time nickname user') +Message = collections.namedtuple('Message', 'txt nick_color time str_time nickname user') class TextBuffer(object): """ @@ -45,8 +45,11 @@ class TextBuffer(object): self.windows.append(win) def add_message(self, txt, time=None, nickname=None, nick_color=None, history=None): - msg = Message(txt='%s\x19o'%(txt,), nick_color=nick_color, - time=time or datetime.now(), nickname=nickname, user=None) + time = time or datetime.now() + msg = Message(txt='%s'%(txt,), nick_color=nick_color, + time=time, str_time=time.strftime("%Y-%m-%d %H:%M:%S")\ + if history else time.strftime("%H:%M:%S"),\ + nickname=nickname, user=None) self.messages.append(msg) while len(self.messages) > self.messages_nb_limit: self.messages.pop(0) diff --git a/src/windows.py b/src/windows.py index 6d71e28e..1aff61bc 100644 --- a/src/windows.py +++ b/src/windows.py @@ -1,18 +1,9 @@ -# Copyright 2010-2011 Le Coz Florent +# Copyright 2010-2011 Florent Le Coz # # 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 . +# it under the terms of the MIT license. See the COPYING file. """ Define all the windows. @@ -37,6 +28,7 @@ from threading import Lock from contact import Contact, Resource from roster import RosterGroup, roster +from poopt import cut_text # from message import Line from tabs import MIN_WIDTH, MIN_HEIGHT @@ -50,7 +42,10 @@ import wcwidth import singleton import collections -Line = collections.namedtuple('Line', 'text text_offset nickname_color time nickname') +# msg is a reference to the corresponding Message tuple. text_start and text_end are the position +# delimiting the text in this line. +# first is a bool telling if this is the first line of the message. +Line = collections.namedtuple('Line', 'msg start_pos end_pos first') g_lock = Lock() @@ -544,23 +539,7 @@ class TextWin(Win): Return the number of lines that are built for the given message. """ - 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]) - + log.debug('LEEEN: %s [%s]' % (len(message.txt), repr(message.txt))) if message is None: # line separator self.built_lines.append(None) return 0 @@ -574,7 +553,7 @@ class TextWin(Win): offset = 20 else: offset = 9 - if theme.CHAR_TIME_RIGHT: + if theme.CHAR_TIME_LEFT: offset += 1 if theme.CHAR_TIME_RIGHT: offset += 1 @@ -586,36 +565,21 @@ class TextWin(Win): if nick: offset += wcwidth.wcswidth(nick) + 2 # + nick + spaces length first = True - nb = 0 - while txt != '': - (txt, cutted_txt) = cut_text(txt, self.width-offset-1) - if first: - if message.nick_color: - color = message.nick_color - elif message.user: - color = message.user.color - else: - color = None - else: - color = None - if first: - if history: - time = message.time.strftime("%Y-%m-%d %H:%M:%S") - else: - time = message.time.strftime("%H:%M:%S") - nickname = nick - else: - time = None - nickname = None - self.built_lines.append(Line(text=cutted_txt, - text_offset=offset, - nickname_color=color, time=time, - nickname=nickname)) - nb += 1 + start_pos = 0 + end_pos = 0 + text_len = len(txt) + offset = (3 if message.nickname else 1) + len(message.str_time)+len(message.nickname or '') + lines = cut_text(txt, self.width-offset-1) + for line in lines: + self.built_lines.append(Line(msg=message, + start_pos=line[0], + end_pos=line[1], + first=first)) first = False + start_pos = next_start_pos while len(self.built_lines) > self.lines_nb_limit: self.built_lines.pop(0) - return nb + return len(lines) def refresh(self, room): log.debug('Refresh: %s'%self.__class__.__name__) @@ -632,15 +596,23 @@ class TextWin(Win): if line is None: self.write_line_separator() else: - self.write_time(line.time) - self.write_nickname(line.nickname, line.nickname_color) + msg = line.msg + if line.first: + if msg.nick_color: + color = msg.nick_color + elif msg.user: + color = msg.user.color + else: + color = None + self.write_time(msg.str_time) + self.write_nickname(msg.nickname, color) if y != self.height-1: self.addstr('\n') self._win.attrset(0) for y, line in enumerate(lines): if not line: continue - self.write_text(y, line.text_offset, line.text) + self.write_text(y, (3 if line.msg.nickname else 1) + len(line.msg.str_time)+len(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) @@ -991,10 +963,6 @@ class Input(Win): """ Shell-like completion """ - if " " in self.text.strip() or add_after is not None: - after = " " # don't put the "," if it's not the begining of the sentence - else: - after = config.get('after_completion', ',')+" " (y, x) = self._win.getyx() if self.text != '': begin = self.text.split()[-1].lower() -- cgit v1.2.3 From fa5b5fc45dfb6e3a736954f0a916541fda963305 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 9 Sep 2011 18:43:20 +0200 Subject: Make it work. MAY segfault. Need intensive testing. Should be A. LOT. FASTER. though. --- src/pooptmodule.c | 28 +++++++++++++++------------- src/text_buffer.py | 2 +- src/windows.py | 3 --- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/pooptmodule.c b/src/pooptmodule.c index cdc0d127..289313f3 100644 --- a/src/pooptmodule.c +++ b/src/pooptmodule.c @@ -17,7 +17,6 @@ otherwise it will just use the equivalent python functions. */ #include "Python.h" PyObject *ErrorObject; -#define DEBUG(...) fprintf(stderr, __VA_ARGS__) /*** The module functions @@ -35,11 +34,11 @@ PyDoc_STRVAR(poopt_cut_text_doc, "cut_text(width, text)\n\n\nReturn the list of static PyObject *poopt_cut_text(PyObject *self, PyObject *args) { - int length; + /* int length; */ unsigned char *buffer; int width; - if (PyArg_ParseTuple(args, "es#i", NULL, &buffer, &length, &width) == 0) + if (PyArg_ParseTuple(args, "si", &buffer, &width) == 0) return NULL; int bpos = 0; /* the real position in the char* */ @@ -49,7 +48,7 @@ static PyObject *poopt_cut_text(PyObject *self, PyObject *args) PyObject* retlist = PyList_New(0); - while (bpos < length) + while (buffer[bpos]) { if (buffer[bpos] == ' ') last_space = spos; @@ -78,17 +77,20 @@ static PyObject *poopt_cut_text(PyObject *self, PyObject *args) } if (buffer[bpos] == 25) /* \x19 */ { - spos--; - bpos += 1; + spos++; + bpos += 2; } - else if (buffer[bpos] <= 127) /* ASCII char on one byte */ - bpos += 1; - else if (buffer[bpos] <= 195) - bpos += 2; - else if (buffer[bpos] <= 225) - bpos += 3; else - bpos += 4; + if (buffer[bpos] <= 127) /* ASCII char on one byte */ + bpos += 1; + else if (buffer[bpos] >= 194 && buffer[bpos] <= 223) + bpos += 2; + else if (buffer[bpos] >= 224 && buffer[bpos] <= 239) + bpos += 3; + else if (buffer[bpos] >= 240 && buffer[bpos] <= 244) + bpos += 4; + else + return NULL; spos++; } if (PyList_Append(retlist, Py_BuildValue("(i,i)", start_pos, spos)) == -1) diff --git a/src/text_buffer.py b/src/text_buffer.py index 77646aea..a6465da3 100644 --- a/src/text_buffer.py +++ b/src/text_buffer.py @@ -46,7 +46,7 @@ class TextBuffer(object): def add_message(self, txt, time=None, nickname=None, nick_color=None, history=None): time = time or datetime.now() - msg = Message(txt='%s'%(txt,), nick_color=nick_color, + msg = Message(txt='%s\x19o'%(txt,), nick_color=nick_color, time=time, str_time=time.strftime("%Y-%m-%d %H:%M:%S")\ if history else time.strftime("%H:%M:%S"),\ nickname=nickname, user=None) diff --git a/src/windows.py b/src/windows.py index 1aff61bc..59365dc8 100644 --- a/src/windows.py +++ b/src/windows.py @@ -565,8 +565,6 @@ class TextWin(Win): if nick: offset += wcwidth.wcswidth(nick) + 2 # + nick + spaces length first = True - start_pos = 0 - end_pos = 0 text_len = len(txt) offset = (3 if message.nickname else 1) + len(message.str_time)+len(message.nickname or '') lines = cut_text(txt, self.width-offset-1) @@ -576,7 +574,6 @@ class TextWin(Win): end_pos=line[1], first=first)) first = False - start_pos = next_start_pos while len(self.built_lines) > self.lines_nb_limit: self.built_lines.pop(0) return len(lines) -- cgit v1.2.3 From d26845e2a3896755a04a2c338cb2ebb6c9fcc0de Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 9 Sep 2011 18:46:42 +0200 Subject: =?UTF-8?q?and=20that=20file=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 setup.py diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..50d787da --- /dev/null +++ b/setup.py @@ -0,0 +1,16 @@ +from distutils.core import setup, Extension + +module_poopt = Extension('poopt', + sources = ['src/pooptmodule.c']) + +setup (name = 'BuildLines', + version = '0.0.1', + description = 'Poezio Optimizations', + ext_modules = [module_poopt], + author = 'Florent Le Coz', + author_email = 'louiz@louiz.org', + long_description = """ + a python3 module for poezio, used to replace some time-critical + python functions that are too slow. If compiled, poezio will use this module, + otherwise it will just use the equivalent python functions. + """) -- cgit v1.2.3 From 1ed0581357e03112f47e24750cd952075d3174df Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 10 Sep 2011 20:02:01 +0200 Subject: cleanup in build_new_message, and very little speedups as well --- src/windows.py | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/src/windows.py b/src/windows.py index 59365dc8..7264e2ca 100644 --- a/src/windows.py +++ b/src/windows.py @@ -533,13 +533,12 @@ class TextWin(Win): if None not in self.built_lines: self.built_lines.append(None) - def build_new_message(self, message, history=None): + def build_new_message(self, message, history=None, clean=True): """ Take one message, build it and add it to the list Return the number of lines that are built for the given message. """ - log.debug('LEEEN: %s [%s]' % (len(message.txt), repr(message.txt))) if message is None: # line separator self.built_lines.append(None) return 0 @@ -548,35 +547,32 @@ class TextWin(Win): return 0 else: txt = txt.replace('\t', ' ') - # length of the time - if history: - offset = 20 - else: - offset = 9 + nick = message.nickname + if nick and len(nick) >= 25: + nick = nick[:25]+'…' + offset = 1 + len(message.str_time) + if nick: + offset += wcwidth.wcswidth(nick) + 2 # + nick + spaces length + if nick: + offset += wcwidth.wcswidth(nick) + 2 # + nick + spaces length if theme.CHAR_TIME_LEFT: offset += 1 if theme.CHAR_TIME_RIGHT: offset += 1 - nickname = message.nickname - if nickname and len(nickname) >= 25: - nick = nickname[:25]+'…' - else: - nick = nickname - if nick: - offset += wcwidth.wcswidth(nick) + 2 # + nick + spaces length - first = True - text_len = len(txt) - offset = (3 if message.nickname else 1) + len(message.str_time)+len(message.nickname or '') + lines = cut_text(txt, self.width-offset-1) + + first = True for line in lines: self.built_lines.append(Line(msg=message, start_pos=line[0], end_pos=line[1], first=first)) first = False - while len(self.built_lines) > self.lines_nb_limit: - self.built_lines.pop(0) - return len(lines) + if clean: + while len(self.built_lines) > self.lines_nb_limit: + self.built_lines.pop(0) + return len(lines) def refresh(self, room): log.debug('Refresh: %s'%self.__class__.__name__) @@ -654,7 +650,9 @@ class TextWin(Win): def rebuild_everything(self, room): self.built_lines = [] for message in room.messages: - self.build_new_message(message) + self.build_new_message(message, clean=False) + while len(self.built_lines) > self.lines_nb_limit: + self.built_lines.pop(0) def __del__(self): log.debug('** TextWin: deleting %s built lines' % (len(self.built_lines))) -- cgit v1.2.3 From 555b915669a7127302d2b992930f1721a8d0867c Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 10 Sep 2011 20:14:00 +0200 Subject: w t f t f --- src/windows.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/windows.py b/src/windows.py index 7264e2ca..7d138ad2 100644 --- a/src/windows.py +++ b/src/windows.py @@ -540,6 +540,7 @@ class TextWin(Win): message. """ if message is None: # line separator + log.debug('je build NON, cool non ? +++++++++++++++++++++++++++') self.built_lines.append(None) return 0 txt = message.txt @@ -587,6 +588,7 @@ class TextWin(Win): self._win.erase() for y, line in enumerate(lines): if line is None: + log.debug('COUCOU JE SUIS NONE\n\n-----------------') self.write_line_separator() else: msg = line.msg -- cgit v1.2.3 From e84cbf6ba5b748881ea3f99471a39a8f1fde772a Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 11 Sep 2011 03:29:27 +0200 Subject: Make the roster tab shine when someone added you in her roster --- src/core.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/core.py b/src/core.py index e25be58f..340cdf8a 100644 --- a/src/core.py +++ b/src/core.py @@ -656,7 +656,7 @@ class Core(object): roster.add_contact(contact, jid) roster.edit_groups_of_contact(contact, []) contact.set_ask('asked') - self.tabs[0].set_color_state(theme.COLOR_TAB_HIGHLIGHT) + self.get_tab_by_number(0).set_color_state(theme.COLOR_TAB_HIGHLIGHT) self.information('%s wants to subscribe to your presence'%jid, 'Roster') if isinstance(self.current_tab(), tabs.RosterInfoTab): self.refresh_window() @@ -758,6 +758,12 @@ class Core(object): return tab return None + def get_tab_by_number(self, number): + for tab in self.tabs: + if tab.nb == number: + return tab + return None + def get_room_by_name(self, name): """ returns the room that has this name -- cgit v1.2.3 From 1a485318bfc1a3db4cd970785029eeb8b03bf0b3 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 11 Sep 2011 03:32:54 +0200 Subject: Fix a traceback when a contact not yet accepted goes offline --- src/core.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core.py b/src/core.py index 340cdf8a..4a2cc91f 100644 --- a/src/core.py +++ b/src/core.py @@ -337,7 +337,8 @@ class Core(object): return log.debug('on_got_offline: %s' % presence) resource = contact.get_resource_by_fulljid(jid.full) - assert resource + if not resource: + return # If a resource got offline, display the message in the conversation with this # precise resource. self.add_information_message_to_conversation_tab(jid.full, '\x195%s is \x191offline' % (resource.get_jid().full)) -- cgit v1.2.3 From 362ff75e3239110b596429fd142487add12e08a4 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 11 Sep 2011 04:17:17 +0200 Subject: =?UTF-8?q?fixes=20crashes=20on=20too=20small=20size=20(except=20o?= =?UTF-8?q?n=20the=20/configure=20tab,=20but=20that=E2=80=99s=20an=20other?= =?UTF-8?q?=20issue)=20fixes=20#2186?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tabs.py | 18 +++++++++++++++--- src/windows.py | 8 +++++++- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/tabs.py b/src/tabs.py index af4de010..d2145d54 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -14,7 +14,7 @@ Windows are displayed, resized, etc """ MIN_WIDTH = 50 -MIN_HEIGHT = 16 +MIN_HEIGHT = 22 import logging log = logging.getLogger(__name__) @@ -83,6 +83,10 @@ class Tab(object): @staticmethod def resize(scr): Tab.size = (Tab.height, Tab.width) = scr.getmaxyx() + if Tab.height < MIN_HEIGHT or Tab.width < MIN_WIDTH: + Tab.visible = False + else: + Tab.visible = True def complete_commands(self, the_input): """ @@ -666,6 +670,8 @@ class MucTab(ChatTab): """ Resize the whole window. i.e. all its sub-windows """ + if not self.visible: + return 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)) @@ -1015,7 +1021,7 @@ class PrivateTab(ChatTab): self.core.close_tab() def resize(self): - if self.core.information_win_size >= self.height-3: + if self.core.information_win_size >= self.height-3 or not self.visible: return self.text_win.resize(self.height-3-self.core.information_win_size, self.width, 0, 0) self.text_win.rebuild_everything(self._room) @@ -1164,6 +1170,8 @@ class RosterInfoTab(Tab): self.resize() def resize(self): + if not self.visible: + return roster_width = self.width//2 info_width = self.width-roster_width-1 self.v_separator.resize(self.height-2, 1, 0, roster_width) @@ -1519,7 +1527,7 @@ class ConversationTab(ChatTab): self.core.close_tab() def resize(self): - if self.core.information_win_size >= self.height-3: + if self.core.information_win_size >= self.height-3 or not self.visible: return self.text_win.resize(self.height-4-self.core.information_win_size, self.width, 1, 0) self.text_win.rebuild_everything(self._room) @@ -1638,6 +1646,8 @@ class MucListTab(Tab): self.input.refresh() def resize(self): + if not self.visible: + return self.upper_message.resize(1, self.width, 0, 0) column_size = {'node-part': (self.width-5)//4, 'name': (self.width-5)//4*3, @@ -1766,6 +1776,8 @@ class SimpleTextTab(Tab): self.core.close_tab() def resize(self): + if not self.visible: + return self.text_win.resize(self.height-2, self.width, 0, 0) self.tab_win.resize(1, self.width, self.height-2, 0) self.input.resize(1, self.width, self.height-1, 0) diff --git a/src/windows.py b/src/windows.py index 7d138ad2..5b673c21 100644 --- a/src/windows.py +++ b/src/windows.py @@ -93,6 +93,12 @@ class Win(object): except: pass + def move(self, y, x): + try: + self._win.move(y, x) + except: + self._win.move(0, 0) + def addstr_colored(self, text, y=None, x=None): """ Write a string on the window, setting the @@ -105,7 +111,7 @@ class Win(object): one of 'u', 'b', 'c[0-9]' """ if y is not None and x is not None: - self._win.move(y, x) + self.move(y, x) next_attr_char = text.find('\x19') while next_attr_char != -1: if next_attr_char + 1 < len(text): -- cgit v1.2.3 -- cgit v1.2.3