c code that doesn’t work

This commit is contained in:
Florent Le Coz 2011-09-08 17:05:02 +02:00
parent a808187550
commit 2e04c5c77e
5 changed files with 322 additions and 79 deletions

View file

@ -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

277
src/pooptmodule.c Normal file
View file

@ -0,0 +1,277 @@
/* Copyright 2010-2011 Florent Le Coz <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 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); */
/* } */

View file

@ -1,18 +1,9 @@
# Copyright 2010-2011 Le Coz Florent <louiz@louiz.org>
# Copyright 2010-2011 Florent Le Coz <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/>.
# 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)

View file

@ -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)

View file

@ -1,18 +1,9 @@
# Copyright 2010-2011 Le Coz Florent <louiz@louiz.org>
# Copyright 2010-2011 Florent Le Coz <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/>.
# 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()