#include <fcntl.h>
#include <signal.h>
+
+#define DOC_DATA_TYPE struct python_doc
+#define PANE_DATA_PTR_TYPE struct Pane *
+struct Pane;
#include "core.h"
#include "misc.h"
#include "rexel.h"
+struct python_doc {
+ struct doc doc;
+ struct pydoc *pdoc;
+};
+
+#include "core-pane.h"
+
#define SAFE_CI {.key=safe_cast NULL,\
.home=safe_cast NULL,\
.focus=safe_cast NULL,\
DEF_CMD(python_doc_call);
static void python_free_command(struct command *c safe);
-static struct python_command *export_callable(PyObject *callable safe)
+static struct python_command *export_callable(PyObject *callable safe,
+ PyObject *nm)
{
struct python_command *c;
+ const char *name = NULL;
+ int len;
+
+ if (nm && PyUnicode_Check(nm))
+ name = PyUnicode_AsUTF8(nm);
+ if (!name)
+ name = "";
+ len = strlen(name);
list_for_each_entry(c, &exported_commands, lst)
if (c->callable == callable) {
c->c = python_call;
c->c.free = python_free_command;
c->c.refcnt = 0;
+ if (strcmp(name, "handle_close") == 0 ||
+ (len > 10 &&
+ strcmp(name+len-10, "_closed_ok") == 0))
+ c->c.closed_ok = 1;
+ else
+ c->c.closed_ok = 0;
command_get(&c->c);
Py_INCREF(callable);
c->callable = callable;
return c;
}
-typedef struct {
+typedef struct Pane {
PyObject_HEAD;
struct pane *pane;
struct command cmd;
} PaneIter;
static PyTypeObject PaneIterType;
-typedef struct {
+typedef struct pydoc {
PyObject_HEAD;
struct pane *pane;
struct command cmd;
struct map *map;
int map_init;
- struct doc doc;
} Doc;
static PyTypeObject DocType;
pane = p->data;
Py_INCREF(pane);
} else if (p && p->handle && p->handle->func == python_doc_call.func) {
- struct doc *doc = p->data;
- Doc *pdoc = container_of(doc, Doc, doc);
+ struct python_doc *pd = p->doc_data;
+ Doc *pdoc = pd->pdoc;
pane = (Pane*)pdoc;
Py_INCREF(pane);
} else {
return 1;
}
-static void python_interrupt(int sig)
+static bool python_running;
+DEF_CB(handle_alarm)
{
- /* Python code has been running for too long,
- * interrupt it.
- */
- kill(getpid(), 2);
+ if (python_running)
+ PyErr_SetInterrupt();
+ return 1;
}
REDEF_CB(python_call)
Py_BuildValue("ii", ci->x, ci->y));
if (rv && pc->callable) {
- signal(SIGALRM, python_interrupt);
- alarm(10);
+ python_running = True;
ret = PyObject_Call(pc->callable, args, kwds);
- alarm(0);
- signal(SIGALRM, SIG_DFL);
+ python_running = False;
}
Py_DECREF(args);
else if (PyLong_Check(ret))
rv = PyLong_AsLong(ret);
else if (PyBool_Check(ret))
- rv = (ret == Py_True);
+ rv = (ret == Py_True) ? 1 : Efalse;
else if (PyUnicode_Check(ret) && PyUnicode_GET_LENGTH(ret) >= 1)
rv = CHAR_RET(PyUnicode_READ_CHAR(ret, 0));
else
if (doc && doc != Py_None) {
PyObject *tofree = NULL;
char *docs = python_as_string(doc, &tofree);
+
if (docs &&
- strncmp(docs, "handle-range", 12) == 0 &&
+ strstarts(docs, "handle-range") &&
docs[12]) {
char sep = docs[12];
char *s1 = strchr(docs+13, sep);
char *b = strndup(s1+1, s2-(s1+1));
struct python_command *comm =
- export_callable(m);
+ export_callable(m, e);
key_add_range(self->map, a, b,
&comm->c);
free(a); free(b);
}
}
if (docs &&
- strncmp(docs, "handle-prefix:", 14) == 0) {
+ strstarts(docs, "handle-prefix:")) {
char *a = strconcat(self->pane, docs+14);
char *b = strconcat(self->pane,
a, "\xFF\xFF\xFF\xFF");
struct python_command *comm =
- export_callable(m);
+ export_callable(m, e);
key_add_range(self->map, a, b,
&comm->c);
command_put(&comm->c);
if (m && PyMethod_Check(m)) {
PyObject *doc = PyObject_GetAttrString(m, "__doc__");
- if (doc && doc != Py_None) {
- PyObject *tofree = NULL;
- char *docs = python_as_string(doc, &tofree);
- if (docs &&
- strncmp(docs, "handle:", 7) == 0) {
+ char *docs;
+ PyObject *tofree = NULL;
+ if (doc && doc != Py_None &&
+ (docs = python_as_string(doc, &tofree)) != NULL) {
+
+ if (strstarts(docs, "handle:")) {
struct python_command *comm =
- export_callable(m);
+ export_callable(m, e);
key_add(self->map, docs+7, &comm->c);
command_put(&comm->c);
}
- if (docs &&
- strncmp(docs, "handle-list", 11) == 0 &&
+ if (strstarts(docs, "handle-list") &&
docs[11]) {
char sep = docs[11];
char *s1 = docs + 12;
while (s1 && *s1 && *s1 != sep) {
struct python_command *comm =
- export_callable(m);
+ export_callable(m, e);
char *a;
char *s2 = strchr(s1, sep);
if (s2) {
command_put(&comm->c);
}
}
- Py_XDECREF(tofree);
}
+ Py_XDECREF(tofree);
Py_XDECREF(doc);
}
Py_XDECREF(m);
if (p->map)
key_free(p->map);
p->map = NULL;
- if (PyObject_TypeCheck(p, &DocType)) {
- Doc *d = (Doc*)p;
- doc_free(&d->doc, safe_cast pn);
- }
+ if (pn && PyObject_TypeCheck(p, &DocType))
+ doc_free(&pn->doc_data->doc, safe_cast pn);
if (pn)
pane_put(pn);
Py_DECREF(p);
}
-DEF_CMD(python_close_mark)
+DEF_CMD_CLOSED(python_close_mark)
{
struct mark *m = ci->mark;
return 1;
}
-static int __Pane_init(Pane *self safe, PyObject *args, PyObject *kwds,
+static int do_Pane_init(Pane *self safe, PyObject *args, PyObject *kwds,
Pane **parentp safe,
int *zp safe)
{
- Pane *parent = NULL;
int ret;
static const char *keywords[] = {"parent", "z", NULL};
return 0;
/* Pane(parent=None, z=0) */
- ret = PyArg_ParseTupleAndKeywords(args, kwds, "|Oi", (char**)keywords,
- &parent, zp);
+ ret = PyArg_ParseTupleAndKeywords(args, kwds, "O!|i", (char**)keywords,
+ &PaneType, parentp, zp);
if (ret <= 0)
return -1;
- if ((PyObject*)parent == Py_None)
- parent = NULL;
-
- if (parent && !PyObject_TypeCheck(parent, &PaneType)) {
- PyErr_SetString(PyExc_TypeError, "First arg must be edlib.Pane or None");
- return -1;
- }
-
- *parentp = parent;
-
self->map = key_alloc();
key_add(self->map, "Close:mark", &python_close_mark);
self->cmd = python_pane_call;
+ self->cmd.closed_ok = 1;
self->cmd.free = python_pane_free;
if (self->ob_base.ob_type)
self->cmd.name = self->ob_base.ob_type->tp_name;
{
Pane *parent = NULL;
int z = 0;
- int ret = __Pane_init(self, args, kwds, &parent, &z);
+ int ret = do_Pane_init(self, args, kwds, &parent, &z);
if (ret <= 0)
return ret;
+ if (!parent || !parent->pane)
+ return -1;
/* The pane holds a reference to the Pane through the ->handle
* function
*/
Py_INCREF(self);
- self->pane = pane_register(parent ? parent->pane : NULL,
- z, &self->cmd, self);
- if (self->pane)
- pane_get(self->pane);
+ self->pane = pane_register(parent->pane, z, &self->cmd, self);
+ if (!self->pane)
+ return -1;
+
+ pane_get(self->pane);
return 0;
}
static int Doc_init(Doc *self, PyObject *args, PyObject *kwds)
{
Pane *parent = NULL;
+ struct python_doc *pd;
int z = 0;
- int ret = __Pane_init((Pane*safe)self, args, kwds, &parent, &z);
+ int ret = do_Pane_init((Pane*safe)self, args, kwds, &parent, &z);
- if (ret <= 0 || !self)
+ if (ret <= 0)
return ret;
+ if (!self || !parent || !parent->pane)
+ return -1;
self->cmd.func = python_doc_call_func;
- self->pane = __doc_register(parent ? parent->pane : NULL,
- &self->cmd, &self->doc, self, 0);
- if (self->pane)
+ self->pane = doc_register(parent->pane, &self->cmd);
+ if (self->pane) {
pane_get(self->pane);
- self->doc.refcnt = mark_refcnt;
+ pd = self->pane->doc_data;
+ pd->pdoc = self;
+ pd->doc.refcnt = mark_refcnt;
+ }
return 0;
}
return Py_None;
}
-static PyObject *Pane_focus(Pane *self safe, PyObject *args)
+static PyObject *Pane_take_focus(Pane *self safe, PyObject *args)
{
if (!pane_valid(self))
return NULL;
- pane_focus(self->pane);
+ pane_take_focus(self->pane);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *Pane_has_focus(Pane *self safe, PyObject *args)
{
+ Pane *other = NULL;
+ int ret;
+
if (!pane_valid(self))
return NULL;
- if (pane_has_focus(self->pane)) {
+ ret = PyArg_ParseTuple(args, "|O!", &PaneType, &other);
+ if (ret <= 0)
+ return NULL;
+
+ if (pane_has_focus(self->pane, other ? other->pane : NULL)) {
Py_INCREF(Py_True);
return Py_True;
} else {
int rv;
PyObject *s1, *s2;
struct pyret pr;
- int remain;
- sighandler_t oldhan;
if (!pane_valid(self))
return NULL;
return NULL;
}
- remain = alarm(0);
- oldhan = signal(SIGALRM, SIG_DFL);
+ python_running = False;
rv = key_handle(&ci);
- if (oldhan != SIG_DFL) {
- signal(SIGALRM, oldhan);
- alarm(remain);
- }
+ python_running = True;
/* Just in case ... */
PyErr_Clear();
Pane *newparent = NULL;
int ret = PyArg_ParseTuple(args, "O!", &PaneType, &newparent);
- if (ret > 0 && newparent && self->pane && newparent->pane)
+ if (ret > 0 && newparent && self->pane && newparent->pane) {
pane_reparent(self->pane, newparent->pane);
+ if (self->pane->parent != newparent->pane) {
+ PyErr_SetString(PyExc_TypeError, "reparent failed");
+ return NULL;
+ }
+ }
Py_INCREF(Py_None);
return Py_None;
}
"provides an iterator which will iterate over all children"},
{"clone_children", (PyCFunction)Pane_clone_children, METH_VARARGS,
"Clone all children onto the target"},
- {"take_focus", (PyCFunction)Pane_focus, METH_NOARGS,
+ {"take_focus", (PyCFunction)Pane_take_focus, METH_NOARGS,
"Claim the focus for this pane"},
- {"has_focus", (PyCFunction)Pane_has_focus, METH_NOARGS,
+ {"has_focus", (PyCFunction)Pane_has_focus, METH_VARARGS,
"Check if pane is focus of display"},
{"call", (void*)(PyCFunctionWithKeywords)Pane_call, METH_VARARGS|METH_KEYWORDS,
"Call a command from a pane"},
new = p->pane->focus;
if (*which == 'r')
new = pane_root(p->pane);
+ if (*which == 'F')
+ new = pane_focus(p->pane);
if (*which == 'L')
new = pane_leaf(p->pane);
if (new == NULL) {
{"root",
(getter)pane_getpane, (setter)pane_nosetpane,
"Root pane", "r"},
+ {"final_focus",
+ (getter)pane_getpane, (setter)pane_nosetpane,
+ "Final focus pane", "F"},
{"leaf",
(getter)pane_getpane, (setter)pane_nosetpane,
"Leaf pane", "L"},
if (!doc_valid(self))
return NULL;
- m = mark_first(&self->doc);
+ m = mark_first(&self->pane->doc_data->doc);
if (!m) {
Py_INCREF(Py_None);
return Py_None;
PyErr_SetString(PyExc_TypeError, "Mark is NULL");
return NULL;
}
- d = m->mark->owner->data;
+ d = &m->mark->owner->doc;
if (d->refcnt == mark_refcnt)
return PyLong_FromLong(m->mark->ref.o);
return PyLong_FromLong(0);
val = PyLong_AsLong(v);
if (val == -1 && PyErr_Occurred())
return -1;
- d = m->mark->owner->data;
+ d = &m->mark->owner->doc;
if (d->refcnt == mark_refcnt)
m->mark->ref.o = val;
else {
PyErr_SetString(PyExc_TypeError, "Mark is NULL");
return NULL;
}
- d = m->mark->owner->data;
+ d = &m->mark->owner->doc;
if (d->refcnt == mark_refcnt && m->mark->ref.c) {
Py_INCREF(m->mark->ref.c);
return m->mark->ref.c;
PyErr_SetString(PyExc_TypeError, "Mark is NULL");
return -1;
}
- d = m->mark->owner->data;
+ d = &m->mark->owner->doc;
if (d->refcnt != mark_refcnt) {
PyErr_SetString(PyExc_TypeError, "Cannot set ref for non-local mark");
return -1;
* use that instead, so that mark_same() works.
*/
if ((m2 = mark_next(m->mark)) != NULL &&
- ((struct doc *safe)m2->owner->data)->refcnt == mark_refcnt &&
+ m2->owner->doc.refcnt == mark_refcnt &&
m2->ref.c != NULL && v != NULL &&
PyObject_RichCompareBool(v, m2->ref.c, Py_EQ) == 1)
m->mark->ref.c = m2->ref.c;
else if ((m2 = mark_prev(m->mark)) != NULL &&
- ((struct doc *safe)m2->owner->data)->refcnt == mark_refcnt &&
+ m2->owner->doc.refcnt == mark_refcnt &&
m2->ref.c != NULL && v != NULL &&
PyObject_RichCompareBool(v, m2->ref.c, Py_EQ) == 1)
m->mark->ref.c = m2->ref.c;
{NULL} /* Sentinel */
};
-static Mark *mark_new(PyTypeObject *type safe, PyObject *args, PyObject *kwds)
+static Mark *Mark_new(PyTypeObject *type safe, PyObject *args, PyObject *kwds)
{
Mark *self;
.tp_methods = (PyMethodDef*)mark_methods,
.tp_getset = (PyGetSetDef*)mark_getseters,
.tp_init = (initproc)Mark_init,
- .tp_new = (newfunc)mark_new,
+ .tp_new = (newfunc)Mark_new,
.tp_repr = (reprfunc)mark_repr,
.tp_as_number = (PyNumberMethods*)&mark_as_num,
};
return False;
}
} else if (PyCallable_Check(a)) {
- struct python_command *pc = export_callable(a);
+ struct python_command *pc = export_callable(a, NULL);
if (ci->comm2 == NULL)
ci->comm2 = &pc->c;
return False;
}
} else if (PyCallable_Check(a)) {
- struct python_command *pc = export_callable(a);
+ struct python_command *pc = export_callable(a, NULL);
ci->comm2 = &pc->c;
} else {
PyObject *m;
PyConfig config;
char *argv[2]= { "edlib", NULL };
+ sighandler_t sigint;
if (edlib_module_path)
module_dir = strdup(edlib_module_path);
else
module_dir = ".";
+ /* de-register SIGINT while we initialise python,
+ * so that Python thinks that it's registration is
+ * valid - so PyErr_SetInterrupt() don't think there
+ * is a race.
+ */
+ sigint = signal(SIGINT, SIG_DFL);
PyConfig_InitPythonConfig(&config);
config.isolated = 1;
PyConfig_SetBytesArgv(&config, 0, argv);
Py_InitializeFromConfig(&config);
PyConfig_Clear(&config);
+ signal(SIGINT, sigint);
PaneType.tp_new = PyType_GenericNew;
PaneIterType.tp_new = PyType_GenericNew;
PyModule_AddIntConstant(m, "WEOF", 0x3FFFFF);
+ PyModule_AddIntConstant(m, "testing", edlib_testing(ed));
+
Edlib_CommandFailed = PyErr_NewException("edlib.commandfailed", NULL, NULL);
Py_INCREF(Edlib_CommandFailed);
PyModule_AddObject(m, "commandfailed", Edlib_CommandFailed);
EdlibModule = m;
ed_pane = ed;
+ call_comm("global-set-command", ed, &handle_alarm,
+ 0, NULL, "fast-alarm-python");
+
call_comm("global-set-command", ed, &python_load_module,
0, NULL, "global-load-modules:python");
}