2 * Copyright Neil Brown ©2015-2021 <neil@brown.name>
3 * May be distributed under terms of GPLv2 - see file:COPYING
5 * Python3 bindings for edlib.
6 * An edlib command "python-load" will read and execute a python
8 * It can use "edlib.editor" to get the editor instance, and can
9 * use "edlib.call()" to issue edlib commands.
11 * Types available are:
12 * edlib.pane - a generic pane. These form a tree of which edlib.editor
14 * get/set operations for x,y,z,w,h,cx,cy as numbers
15 * changes x,y,w,h call pane_resize()
16 * z cannot be changed (only pane_register() does that )
17 * cx,cy can be changed freely.
18 * 'parent' and 'focus' can be read but not written
19 * method for 'children' provides first child as an iterator.
20 * method abs() converts relative co-ords to absolute.
21 * rel() converts absolute co-ords to relative.
22 * edlib.mark - these reference locations in a document. The document is
23 * not directly accessible, it can only be accessed through
24 * a pane (which may translate events and results).
25 * get/set for viewnum (cannot be set)
26 * iterator for both 'all' and 'view' lists.
29 * edlib.comm - a command which can be used to invoke code in other
30 * module editors. These look like any other python
31 * callable. They cannot be explicitly created, but can
32 * be received from and passed to other commands.
37 /* Need to define stuff that pyconfig needs */
43 //#define PyType_HasFeature __PyType_HasFeature
45 #undef PyType_HasFeature __PyType_HasFeature
46 int PyType_HasFeature(PyTypeObject *type, unsigned long feature);
49 #define Py_INCREF(op) (0)
51 #define Py_DECREF(op) (0)
53 #define Py_XDECREF(op) (0)
55 #define Py_IS_TYPE(ob, type) (ob == (void*)type)
59 #define MARK_DATA_PTR PyObject
60 #define PRIVATE_DOC_REF
72 #define SAFE_CI {.key=safe_cast NULL,\
73 .home=safe_cast NULL,\
74 .focus=safe_cast NULL,\
75 .comm=safe_cast NULL,\
78 static PyObject *Edlib_CommandFailed;
79 static PyObject *EdlibModule;
81 static struct pane *ed_pane;
83 static char *module_dir;
84 static char *python_as_string(PyObject *s, PyObject **tofree safe);
86 /* Python commands visible to edlib are wrapped in
87 * the python_command. There is only one per callback,
88 * so that edlib code can compare for equalty.
90 struct python_command {
95 static LIST_HEAD(exported_commands);
98 DEF_CMD(python_pane_call);
99 DEF_CMD(python_doc_call);
100 static void python_free_command(struct command *c safe);
102 static struct python_command *export_callable(PyObject *callable safe)
104 struct python_command *c;
106 list_for_each_entry(c, &exported_commands, lst)
107 if (c->callable == callable) {
112 c = malloc(sizeof(*c));
114 c->c.free = python_free_command;
118 c->callable = callable;
119 list_add(&c->lst, &exported_commands);
130 static PyTypeObject PaneType;
136 static PyTypeObject PaneIterType;
146 static PyTypeObject DocType;
152 static PyTypeObject MarkType;
153 static void mark_refcnt(struct mark *m safe, int inc);
157 struct command *comm;
159 static PyTypeObject CommType;
161 static inline bool pane_valid(Pane *p safe)
163 if (p->pane && p->pane->handle)
165 PyErr_SetString(PyExc_TypeError, "Pane has been freed");
169 static inline bool doc_valid(Doc *p safe)
171 if (p->pane && p->pane->handle)
173 PyErr_SetString(PyExc_TypeError, "Doc pane has been freed");
177 static bool get_cmd_info(struct cmd_info *ci safe, PyObject *args safe, PyObject *kwds,
178 PyObject **s1 safe, PyObject **s2 safe);
180 static int in_pane_frompane = 0;
181 static inline PyObject *safe Pane_Frompane(struct pane *p)
184 if (p && p->handle && p->handle->func == python_pane_call.func) {
187 } else if (p && p->handle && p->handle->func == python_doc_call.func) {
188 struct doc *doc = p->data;
189 Doc *pdoc = container_of(doc, Doc, doc);
193 in_pane_frompane = 1;
194 pane = (Pane *)PyObject_CallObject((PyObject*)&PaneType, NULL);
195 in_pane_frompane = 0;
199 return (PyObject*)pane;
202 static inline PyObject *safe Mark_Frommark(struct mark *m safe)
206 if (m->mtype == &MarkType && m->mdata) {
207 /* This is a vmark, re-use the PyObject */
211 mark = (Mark *)PyObject_CallObject((PyObject*)&MarkType, NULL);
214 return (PyObject*)mark;
217 static inline PyObject *safe Comm_Fromcomm(struct command *c safe)
219 Comm *comm = (Comm *)PyObject_CallObject((PyObject*)&CommType, NULL);
221 comm->comm = command_get(c);
222 return (PyObject*)comm;
225 static PyObject *py_LOG(PyObject *self, PyObject *args);
226 static void PyErr_LOG(void)
228 /* cribbed from https://groups.google.com/forum/#!topic/comp.lang.python/khLrxC6EOKc */
229 char *errorMsg = NULL;
230 PyObject *modIO = NULL;
231 PyObject *modTB = NULL;
232 PyObject *obFuncStringIO = NULL;
233 PyObject *obIO = NULL;
234 PyObject *obFuncTB = NULL;
235 PyObject *argsTB = NULL;
236 PyObject *obResult = NULL;
237 PyObject *tofree = NULL;
238 PyObject *exc_typ, *exc_val, *exc_tb;
240 if (!PyErr_Occurred())
243 PyErr_Fetch(&exc_typ, &exc_val, &exc_tb);
244 PyErr_NormalizeException(&exc_typ, &exc_val, &exc_tb);
246 /* Import the modules we need - StringIO and traceback */
247 errorMsg = "Can't import io";
248 modIO = PyImport_ImportModule("io");
252 errorMsg = "Can't import traceback";
253 modTB = PyImport_ImportModule("traceback");
257 /* Construct a cStringIO object */
258 errorMsg = "Can't find io.StringIO";
259 obFuncStringIO = PyObject_GetAttrString(modIO, "StringIO");
262 errorMsg = "io.StringIO() failed";
263 obIO = PyObject_CallObject(obFuncStringIO, NULL);
267 /* Get the traceback.print_exception function, and call it. */
268 errorMsg = "Can't find traceback.print_exception";
269 obFuncTB = PyObject_GetAttrString(modTB, "print_exception");
272 errorMsg = "can't make print_exception arguments";
273 argsTB = Py_BuildValue("OOOOO",
274 exc_typ ? exc_typ : Py_None,
275 exc_val ? exc_val : Py_None,
276 exc_tb ? exc_tb : Py_None,
282 errorMsg = "traceback.print_exception() failed";
283 obResult = PyObject_CallObject(obFuncTB, argsTB);
289 /* Now call the getvalue() method in the StringIO instance */
290 Py_DECREF(obFuncStringIO);
291 errorMsg = "cant find getvalue function";
292 obFuncStringIO = PyObject_GetAttrString(obIO, "getvalue");
295 Py_XDECREF(obResult);
296 errorMsg = "getvalue() failed.";
297 obResult = PyObject_CallObject(obFuncStringIO, NULL);
301 /* And it should be a string all ready to go - report it. */
302 errorMsg = python_as_string(obResult, &tofree);;
303 LOG("Python error:\n%s", errorMsg);
306 call("editor:notify:Message:broadcast",ed_pane, 0, NULL,
307 "Python Error - see log") <= 0))
308 /* Failed to alert anyone - write to stderr */
309 fwrite(errorMsg, 1, strlen(errorMsg), stderr);
317 Py_XDECREF(obFuncStringIO);
319 Py_XDECREF(obFuncTB);
321 Py_XDECREF(obResult);
330 const char *fname = ci->str;
332 PyObject *globals, *main_mod;
337 fp = fopen(fname, "r");
341 main_mod = PyImport_AddModule("__main__");
342 if (main_mod == NULL)
344 globals = PyModule_GetDict(main_mod);
346 Ed = Pane_Frompane(ci->home);
347 PyDict_SetItemString(globals, "editor", Ed);
348 PyDict_SetItemString(globals, "edlib", EdlibModule);
349 PyRun_FileExFlags(fp, fname, Py_file_input, globals, globals, 0, NULL);
356 DEF_CMD(python_load_module)
358 const char *name = ci->str;
360 PyObject *globals, *main_mod;
366 snprintf(buf, sizeof(buf), "%s/python/%s.py", module_dir, name);
367 fp = fopen(buf, "r");
371 LOG("Loading python module %s from %s", name, buf);
372 main_mod = PyImport_AddModule("__main__");
373 if (main_mod == NULL)
375 globals = PyModule_GetDict(main_mod);
377 Ed = Pane_Frompane(ci->home);
378 PyDict_SetItemString(globals, "editor", Ed);
379 PyDict_SetItemString(globals, "pane", Pane_Frompane(ci->focus));
380 PyDict_SetItemString(globals, "edlib", EdlibModule);
381 PyRun_FileExFlags(fp, buf, Py_file_input, globals, globals, 0, NULL);
388 static PyObject *safe python_string(const char *s safe)
391 while (*c && !(*c & 0x80))
394 /* must be Unicode */
395 return safe_cast PyUnicode_DecodeUTF8(s, strlen(s), NULL);
397 return safe_cast Py_BuildValue("s", s);
400 static char *python_as_string(PyObject *s, PyObject **tofree safe)
402 if (s && PyUnicode_Check(s)) {
403 s = PyUnicode_AsUTF8String(s);
406 if (s && PyBytes_Check(s)) {
407 char *ret = PyBytes_AsString(s);
408 unsigned char *r = (unsigned char*)ret;
409 if (r && r[0] == 0xef && r[1] == 0xbb && r[2] == 0xbf)
410 /* UTF-8 Byte Order Mark */
418 static int dict_add(PyObject *kwds, char *name, PyObject *val)
422 PyDict_SetItemString(kwds, name, val);
427 static void python_interrupt(int sig)
429 /* Python code has been running for too long,
435 REDEF_CB(python_call)
437 struct python_command *pc = container_of(ci->comm, struct python_command, c);
438 PyObject *ret = NULL, *args, *kwds;
441 args = safe_cast Py_BuildValue("(s)", ci->key);
443 rv = rv && dict_add(kwds, "home", Pane_Frompane(ci->home));
444 rv = rv && dict_add(kwds, "focus",
445 Pane_Frompane(ci->focus));
446 rv = rv && dict_add(kwds, "mark",
447 ci->mark ? Mark_Frommark(ci->mark):
448 (Py_INCREF(Py_None), Py_None));
449 rv = rv && dict_add(kwds, "mark2",
450 ci->mark2 ? Mark_Frommark(ci->mark2):
451 (Py_INCREF(Py_None), Py_None));
452 rv = rv && dict_add(kwds, "str",
453 ci->str ? python_string(ci->str):
454 (Py_INCREF(Py_None), safe_cast Py_None));
455 rv = rv && dict_add(kwds, "str2",
456 ci->str2 ? python_string(ci->str2):
457 (Py_INCREF(Py_None), safe_cast Py_None));
458 rv = rv && dict_add(kwds, "comm", Comm_Fromcomm(ci->comm));
459 rv = rv && dict_add(kwds, "comm2",
460 ci->comm2 ? Comm_Fromcomm(ci->comm2):
461 (Py_INCREF(Py_None), Py_None));
462 rv = rv && dict_add(kwds, "num",
463 Py_BuildValue("i", ci->num));
464 rv = rv && dict_add(kwds, "rpt_num",
465 Py_BuildValue("i", RPT_NUM(ci)));
466 rv = rv && dict_add(kwds, "num2",
467 Py_BuildValue("i", ci->num2));
468 rv = rv && dict_add(kwds, "xy",
469 Py_BuildValue("ii", ci->x, ci->y));
471 if (rv && pc->callable) {
472 signal(SIGALRM, python_interrupt);
474 ret = PyObject_Call(pc->callable, args, kwds);
476 signal(SIGALRM, SIG_DFL);
483 /* FIXME cancel error?? */
488 else if (PyLong_Check(ret))
489 rv = PyLong_AsLong(ret);
490 else if (PyBool_Check(ret))
491 rv = (ret == Py_True);
492 else if (PyUnicode_Check(ret) && PyUnicode_GET_LENGTH(ret) >= 1)
493 rv = CHAR_RET(PyUnicode_READ_CHAR(ret, 0));
500 REDEF_CMD(python_doc_call)
502 int rv = python_pane_call_func(ci);
503 if (rv == Efallthrough)
504 rv = key_lookup(doc_default_cmd, ci);
508 static void do_map_init(Pane *self safe)
511 PyObject *l = PyObject_Dir((PyObject*)self);
514 if (!self->map || !self->pane || !l)
517 /* First add the ranges, so individuals can over-ride them */
518 for (i = 0; i < n ; i++) {
519 PyObject *e = PyList_GetItem(l, i);
520 PyObject *m = PyObject_GetAttr((PyObject*)self, e);
522 if (m && PyMethod_Check(m)) {
523 PyObject *doc = PyObject_GetAttrString(m, "__doc__");
524 if (doc && doc != Py_None) {
525 PyObject *tofree = NULL;
526 char *docs = python_as_string(doc, &tofree);
528 strncmp(docs, "handle-range", 12) == 0 &&
531 char *s1 = strchr(docs+13, sep);
532 char *s2 = s1 ? strchr(s1+1, sep) : NULL;
534 char *a = strndup(docs+13, s1-(docs+13));
535 char *b = strndup(s1+1, s2-(s1+1));
537 struct python_command *comm =
539 key_add_range(self->map, a, b,
542 command_put(&comm->c);
546 strncmp(docs, "handle-prefix:", 14) == 0) {
547 char *a = strconcat(self->pane, docs+14);
548 char *b = strconcat(self->pane,
549 a, "\xFF\xFF\xFF\xFF");
550 struct python_command *comm =
552 key_add_range(self->map, a, b,
554 command_put(&comm->c);
562 /* Now add the non-ranges */
563 for (i = 0; i < n ; i++) {
564 PyObject *e = PyList_GetItem(l, i);
565 PyObject *m = PyObject_GetAttr((PyObject*)self, e);
567 if (m && PyMethod_Check(m)) {
568 PyObject *doc = PyObject_GetAttrString(m, "__doc__");
569 if (doc && doc != Py_None) {
570 PyObject *tofree = NULL;
571 char *docs = python_as_string(doc, &tofree);
573 strncmp(docs, "handle:", 7) == 0) {
574 struct python_command *comm =
576 key_add(self->map, docs+7, &comm->c);
577 command_put(&comm->c);
580 strncmp(docs, "handle-list", 11) == 0 &&
583 char *s1 = docs + 12;
584 while (s1 && *s1 && *s1 != sep) {
585 struct python_command *comm =
588 char *s2 = strchr(s1, sep);
590 a = strndup(s1, s2-s1);
596 key_add(self->map, a, &comm->c);
598 command_put(&comm->c);
611 REDEF_CB(python_pane_call)
613 Pane *home = container_of(ci->comm, Pane, cmd);
615 if (!home || !home->map)
620 return key_lookup(home->map, ci);
623 static Pane *pane_new(PyTypeObject *type safe, PyObject *args, PyObject *kwds)
627 self = (Pane *)type->tp_alloc(type, 0);
634 static Doc *Doc_new(PyTypeObject *type safe, PyObject *args, PyObject *kwds)
638 self = (Doc *)type->tp_alloc(type, 0);
645 static void python_pane_free(struct command *c safe)
647 Pane *p = container_of(c, Pane, cmd);
648 /* pane has been closed */
653 if (PyObject_TypeCheck(p, &DocType)) {
660 static int __Pane_init(Pane *self safe, PyObject *args, PyObject *kwds,
666 static char *keywords[] = {"parent", "z", NULL};
669 PyErr_SetString(PyExc_TypeError, "Pane already initialised");
672 /* Pane(parent, handler, data, z=0 */
673 if (in_pane_frompane)
674 /* An internal Pane_Frompane call - it will set .pane,
675 * and we don't want a .handler.
679 ret = PyArg_ParseTupleAndKeywords(args, kwds, "|Oi", keywords,
684 if ((PyObject*)parent == Py_None)
687 if (parent && !PyObject_TypeCheck(parent, &PaneType)) {
688 PyErr_SetString(PyExc_TypeError, "First arg must be edlib.Pane or None");
694 self->map = key_alloc();
695 self->cmd = python_pane_call;
696 self->cmd.free = python_pane_free;
701 static int Pane_init(Pane *self safe, PyObject *args, PyObject *kwds)
705 int ret = __Pane_init(self, args, kwds, &parent, &z);
710 /* The pane holds a reference to the Pane through the ->handle
714 self->pane = pane_register(parent ? parent->pane : NULL,
715 z, &self->cmd, self);
719 static int Doc_init(Doc *self, PyObject *args, PyObject *kwds)
723 int ret = __Pane_init((Pane*safe)self, args, kwds, &parent, &z);
725 if (ret <= 0 || !self)
728 self->cmd.func = python_doc_call_func;
729 self->pane = __doc_register(parent ? parent->pane : NULL,
730 &self->cmd, &self->doc, self, 0);
731 self->doc.refcnt = mark_refcnt;
735 static inline void do_free(PyObject *ob safe)
737 if (ob->ob_type && ob->ob_type->tp_free)
738 ob->ob_type->tp_free(ob);
741 static void pane_dealloc(Pane *self safe)
743 do_free((PyObject*safe)self);
746 static PyObject *pane_children(Pane *self safe, PyObject *args)
750 if (!pane_valid(self))
752 ret = (PaneIter*)PyObject_CallObject((PyObject*)&PaneIterType, NULL);
754 if (list_empty(&self->pane->children))
757 ret->pane = list_first_entry(&self->pane->children,
758 struct pane, siblings);
760 return (PyObject*)ret;
763 static Pane *pane_iter_new(PyTypeObject *type safe, PyObject *args, PyObject *kwds)
767 self = (Pane *)type->tp_alloc(type, 0);
773 static void paneiter_dealloc(PaneIter *self safe)
775 do_free((PyObject*safe)self);
778 static PyObject *Pane_clone_children(Pane *self safe, PyObject *args)
783 if (!pane_valid(self))
786 ret = PyArg_ParseTuple(args, "O!", &PaneType, &other);
787 if (ret <= 0 || !other)
790 pane_clone_children(self->pane, other->pane);
795 static PyObject *Pane_focus(Pane *self safe, PyObject *args)
797 if (!pane_valid(self))
800 pane_focus(self->pane);
805 static PyObject *Pane_has_focus(Pane *self safe, PyObject *args)
807 if (!pane_valid(self))
810 if (pane_has_focus(self->pane)) {
819 static PyObject *Pane_refresh(Pane *self safe, PyObject *args)
821 if (!pane_valid(self))
824 pane_refresh(self->pane);
829 static PaneIter *pane_this_iter(PaneIter *self safe)
835 static PyObject *pane_iter_next(PaneIter *self safe)
839 /* Reached the end */
841 ret = Pane_Frompane(self->pane);
842 if (self->pane->siblings.next == &self->pane->parent->children)
843 /* Reached the end of the list */
846 self->pane = list_next_entry(self->pane, siblings);
858 struct pyret *pr = container_of(ci->comm, struct pyret, comm);
859 struct pane *p = ci->focus;
865 pr->ret = Pane_Frompane(ci->focus);
871 struct pyret *pr = container_of(ci->comm, struct pyret, comm);
877 if (ci->mark->viewnum == MARK_UNGROUPED) {
878 /* Cannot rely on this mark persisting, take a copy */
879 struct mark *m = mark_dup(ci->mark);
880 pr->ret = Mark_Frommark(m);
881 m->mtype = (void*)pr->ret;
883 pr->ret = Mark_Frommark(ci->mark);
889 struct pyret *pr = container_of(ci->comm, struct pyret, comm);
895 pr->ret = Mark_Frommark(ci->mark2);
901 struct pyret *pr = container_of(ci->comm, struct pyret, comm);
907 pr->ret = python_string(ci->str);
913 struct pyret *pr = container_of(ci->comm, struct pyret, comm);
919 pr->ret = safe_cast PyBytes_FromStringAndSize(ci->str, ci->num);
925 struct pyret *pr = container_of(ci->comm, struct pyret, comm);
931 pr->ret = Comm_Fromcomm(ci->comm2);
935 static struct command *map_ret(char *ret safe)
937 if (strcmp(ret, "focus") == 0)
939 if (strcmp(ret, "mark") == 0)
941 if (strcmp(ret, "mark2") == 0)
943 if (strcmp(ret, "str") == 0)
945 if (strcmp(ret, "bytes") == 0)
947 if (strcmp(ret, "comm") == 0)
952 static bool handle_ret(PyObject *kwds, struct cmd_info *ci safe,
953 struct pyret *pr safe)
957 PyObject *ret, *s3 = NULL;
959 memset(pr, 0, sizeof(*pr));
961 ret = kwds ? PyDict_GetItemString(kwds, "ret") : NULL;
965 if (!PyUnicode_Check(ret) ||
966 (rets = python_as_string(ret, &s3)) == NULL) {
967 PyErr_SetString(PyExc_TypeError, "ret= must be given a string");
970 if (strcmp(rets, "char") == 0) {
975 PyErr_SetString(PyExc_TypeError, "ret= not permitted with comm2");
981 PyErr_SetString(PyExc_TypeError, "ret= type not valid");
986 ci->comm2 = &pr->comm;
992 static void set_err(int rv)
996 PyErr_SetObject(Edlib_CommandFailed,
997 PyUnicode_FromFormat("Enoarg"));
1000 PyErr_SetObject(Edlib_CommandFailed,
1001 PyUnicode_FromFormat("Einval"));
1004 PyErr_SetObject(Edlib_CommandFailed,
1005 PyUnicode_FromFormat("Enosup"));
1008 PyErr_SetObject(Edlib_CommandFailed,
1009 PyUnicode_FromFormat("Efail"));
1012 PyErr_SetObject(Edlib_CommandFailed,
1013 PyUnicode_FromFormat("%d", rv));
1017 static PyObject *choose_ret(int rv, struct pyret *pr safe)
1019 if (pr->comm.func && rv >= 0) {
1025 Py_XDECREF(pr->ret);
1030 if (pr->return_char) {
1032 Py_INCREF(Py_False);
1035 if (rv == CHAR_RET(WEOF)) {
1039 return PyUnicode_FromFormat("%c", rv & 0x1FFFFF);
1041 return PyLong_FromLong(rv);
1044 static PyObject *Pane_call(Pane *self safe, PyObject *args safe, PyObject *kwds)
1046 struct cmd_info ci = SAFE_CI;
1052 if (!pane_valid(self))
1055 ci.home = self->pane;
1057 if (!get_cmd_info(&ci, args, kwds, &s1, &s2) ||
1058 !handle_ret(kwds, &ci, &pr)) {
1059 Py_XDECREF(s1); Py_XDECREF(s2);
1060 command_put(ci.comm2);
1065 rv = key_handle(&ci);
1068 /* Just in case ... */
1071 Py_XDECREF(s1); Py_XDECREF(s2);
1072 command_put(ci.comm2);
1074 return choose_ret(rv, &pr);
1077 static PyObject *pane_direct_call(Pane *self safe, PyObject *args safe, PyObject *kwds)
1079 struct cmd_info ci = SAFE_CI;
1084 if (!pane_valid(self))
1087 ci.home = self->pane;
1089 if (!get_cmd_info(&ci, args, kwds, &s1, &s2) ||
1090 !handle_ret(kwds, &ci, &pr)) {
1091 Py_XDECREF(s1); Py_XDECREF(s2);
1092 command_put(ci.comm2);
1096 ci.comm = ci.home->handle;
1097 rv = ci.comm->func(&ci);
1099 Py_XDECREF(s1); Py_XDECREF(s2);
1100 command_put(ci.comm2);
1101 return choose_ret(rv, &pr);
1104 static PyObject *Pane_notify(Pane *self safe, PyObject *args safe, PyObject *kwds)
1106 struct cmd_info ci = SAFE_CI;
1110 if (!pane_valid(self))
1113 ci.home = self->pane;
1115 if (!get_cmd_info(&ci, args, kwds, &s1, &s2)) {
1116 Py_XDECREF(s1); Py_XDECREF(s2);
1117 command_put(ci.comm2);
1121 rv = home_pane_notify(ci.home, ci.key, ci.focus, ci.num, ci.mark, ci.str,
1122 ci.num2, ci.mark2, ci.str2,
1125 Py_XDECREF(s1); Py_XDECREF(s2);
1126 command_put(ci.comm2);
1131 return PyLong_FromLong(rv);
1134 static PyObject *Pane_mapxy(Pane *self safe, PyObject *args)
1140 int ret = PyArg_ParseTuple(args, "O!hh", &PaneType, &other, &x, &y);
1141 if (ret <= 0 || !self->pane || !other || !other->pane)
1144 xy = pane_mapxy(other->pane, self->pane, x, y, False);
1145 return Py_BuildValue("ii", xy.x, xy.y);
1148 static PyObject *Pane_clipxy(Pane *self safe, PyObject *args)
1154 int ret = PyArg_ParseTuple(args, "O!hh", &PaneType, &other, &x, &y);
1155 if (ret <= 0 || !self->pane || !other || !other->pane)
1158 xy = pane_mapxy(other->pane, self->pane, x, y, True);
1159 return Py_BuildValue("ii", xy.x, xy.y);
1162 static PyObject *Pane_add_notify(Pane *self safe, PyObject *args)
1166 int ret = PyArg_ParseTuple(args, "O!s", &PaneType, &other, &event);
1167 if (ret <= 0 || !other || !event)
1169 if (self->pane && other->pane)
1170 pane_add_notify(self->pane, other->pane, event);
1176 static PyObject *Pane_drop_notify(Pane *self safe, PyObject *args)
1179 int ret = PyArg_ParseTuple(args, "s", &event);
1180 if (ret <= 0 || !event)
1183 pane_drop_notifiers(self->pane, event);
1189 static PyObject *Pane_damaged(Pane *self safe, PyObject *args)
1191 int damage = DAMAGED_REFRESH;
1192 int ret = PyArg_ParseTuple(args, "|i", &damage);
1196 pane_damaged(self->pane, damage);
1202 static PyObject *Pane_close(Pane *self safe, PyObject *args)
1204 struct pane *p = self->pane;
1213 static PyObject *Pane_get_scale(Pane *self safe, PyObject *args)
1215 struct pane *p = self->pane;
1216 struct xy xy = {1000, 1000};
1220 return Py_BuildValue("ii", xy.x, xy.y);
1223 static PyObject *Pane_mychild(Pane *self safe, PyObject *args)
1226 int ret = PyArg_ParseTuple(args, "O!", &PaneType, &child);
1227 if (ret <= 0 || !child)
1229 if (self->pane && child->pane) {
1230 struct pane *p = pane_my_child(self->pane, child->pane);
1232 return Pane_Frompane(p);
1238 static PyObject *Pane_clip(Pane *self safe, PyObject *args)
1240 Mark *start = NULL, *end = NULL;
1243 int ret = PyArg_ParseTuple(args, "iO!O!|i", &view, &MarkType, &start,
1244 &MarkType, &end, &tostart);
1246 if (ret > 0 && start && end && self->pane &&
1247 start->mark && end->mark && view >= 0)
1248 marks_clip(self->pane, start->mark, end->mark, view, self->pane,
1254 static PyObject *Pane_reparent(Pane *self safe, PyObject *args)
1256 Pane *newparent = NULL;
1257 int ret = PyArg_ParseTuple(args, "O!", &PaneType, &newparent);
1259 if (ret > 0 && newparent && self->pane && newparent->pane)
1260 pane_reparent(self->pane, newparent->pane);
1265 static PyObject *Pane_move_after(Pane *self safe, PyObject *args)
1268 int ret = PyArg_ParseTuple(args, "O", &peer);
1270 if (ret > 0 && peer && self->pane) {
1271 if ((PyObject*)peer == Py_None)
1272 pane_move_after(self->pane, NULL);
1273 else if (PyObject_TypeCheck(peer, &PaneType) && peer->pane)
1274 pane_move_after(self->pane, peer->pane);
1280 static PyObject *Pane_step(Pane *self safe, PyObject *args, int dir, int move)
1283 int ret = PyArg_ParseTuple(args, "O!", &MarkType, &m);
1286 if (!pane_valid(self))
1288 if (ret <= 0 || !m) {
1289 PyErr_SetString(PyExc_TypeError, "Arg must be a mark");
1294 wch = doc_move(self->pane, m->mark, dir);
1296 wch = doc_pending(self->pane, m->mark, dir);
1301 return PyUnicode_FromFormat("%c", wch);
1304 static PyObject *Pane_step_next(Pane *self safe, PyObject *args)
1306 return Pane_step(self, args, 1, 1);
1309 static PyObject *Pane_step_prev(Pane *self safe, PyObject *args)
1311 return Pane_step(self, args, -1, 1);
1314 static PyObject *Pane_step_following(Pane *self safe, PyObject *args)
1316 return Pane_step(self, args, 1, 0);
1319 static PyObject *Pane_step_prior(Pane *self safe, PyObject *args)
1321 return Pane_step(self, args, -1, 0);
1324 static PyMethodDef pane_methods[] = {
1325 {"close", (PyCFunction)Pane_close, METH_NOARGS,
1327 {"children", (PyCFunction)pane_children, METH_NOARGS,
1328 "provides an iterator which will iterate over all children"},
1329 {"clone_children", (PyCFunction)Pane_clone_children, METH_VARARGS,
1330 "Clone all children onto the target"},
1331 {"take_focus", (PyCFunction)Pane_focus, METH_NOARGS,
1332 "Claim the focus for this pane"},
1333 {"has_focus", (PyCFunction)Pane_has_focus, METH_NOARGS,
1334 "Check if pane is focus of display"},
1335 {"refresh", (PyCFunction)Pane_refresh, METH_NOARGS,
1336 "Trigger refresh on this pane"},
1337 {"call", (void*)(PyCFunctionWithKeywords)Pane_call, METH_VARARGS|METH_KEYWORDS,
1338 "Call a command from a pane"},
1339 {"notify", (void*)(PyCFunctionWithKeywords)Pane_notify, METH_VARARGS|METH_KEYWORDS,
1340 "Send a notification from a pane"},
1341 {"mapxy", (PyCFunction)Pane_mapxy, METH_VARARGS,
1342 "Convert pane-relative co-ords between panes"},
1343 {"clipxy", (PyCFunction)Pane_clipxy, METH_VARARGS,
1344 "Convert pane-relative co-ords between panes, clipping to all panes"},
1345 {"add_notify", (PyCFunction)Pane_add_notify, METH_VARARGS,
1346 "Add notifier for an event on some other pane"},
1347 {"drop_notify", (PyCFunction)Pane_drop_notify, METH_VARARGS,
1348 "Drop notification to this pane for an event"},
1349 {"damaged", (PyCFunction)Pane_damaged, METH_VARARGS,
1350 "Mark pane as damaged"},
1351 {"scale", (PyCFunction)Pane_get_scale, METH_NOARGS,
1352 "Get the x,y scale numbers for this pane"},
1353 {"mychild", (PyCFunction)Pane_mychild, METH_VARARGS,
1354 "Get ancestor of pane which is my child, or None"},
1355 {"clip", (PyCFunction)Pane_clip, METH_VARARGS,
1356 "clip all 'type' marks in the given range"},
1357 {"reparent", (PyCFunction)Pane_reparent, METH_VARARGS,
1358 "Give a pane a new parent"},
1359 {"move_after", (PyCFunction)Pane_move_after, METH_VARARGS,
1360 "Move a pane after another in order of children"},
1361 {"next", (PyCFunction)Pane_step_next, METH_VARARGS,
1362 "Move mark forward returning the character"},
1363 {"prev", (PyCFunction)Pane_step_prev, METH_VARARGS,
1364 "Move mark back returning the character"},
1365 {"following", (PyCFunction)Pane_step_following, METH_VARARGS,
1366 "returning the character after mark"},
1367 {"prior", (PyCFunction)Pane_step_prior, METH_VARARGS,
1368 "returning the character before mark"},
1372 static PyObject *pane_getnum(Pane *p safe, char *which safe)
1380 case 'x': n = p->pane->x; break;
1381 case 'y': n = p->pane->y; break;
1382 case 'w': n = p->pane->w > 0 ? p->pane->w : 1; break;
1383 case 'h': n = p->pane->h > 0 ? p->pane->h : 1; break;
1384 case 'X': n = p->pane->cx; break;
1385 case 'Y': n = p->pane->cy; break;
1386 case 'z': n = p->pane->z; break;
1387 case 'Z': n = p->pane->abs_z; break;
1389 return PyLong_FromLong(n);
1392 static int pane_setnum(Pane *p safe, PyObject *v, char *which safe)
1400 if (*which == 'z') {
1401 PyErr_SetString(PyExc_TypeError, "z cannot be set");
1404 if (*which == 'Z') {
1405 PyErr_SetString(PyExc_TypeError, "abs_z cannot be set");
1408 val = PyLong_AsLong(v);
1409 if (val == -1 && PyErr_Occurred())
1412 x = p->pane->x; y = p->pane->y;
1413 w = p->pane->w; h = p->pane->h;
1415 case 'x': x = val; break;
1416 case 'y': y = val; break;
1417 case 'w': w = val; break;
1418 case 'h': h = val; break;
1419 case 'X': p->pane->cx = val; return 0;
1420 case 'Y': p->pane->cy = val; return 0;
1422 pane_resize(p->pane, x, y, w, h);
1426 static Pane *pane_getpane(Pane *p safe, char *which safe)
1428 struct pane *new = NULL;
1435 new = p->pane->parent;
1437 new = p->pane->focus;
1439 new = pane_root(p->pane);
1441 new = pane_leaf(p->pane);
1444 newpane = (Pane*)Py_None;
1446 newpane = (Pane *)Pane_Frompane(new);
1451 static int pane_nosetpane(Pane *p, PyObject *v, void *which)
1453 PyErr_SetString(PyExc_TypeError, "Cannot set panes");
1457 static PyObject *pane_repr(Pane *self safe)
1461 if (!pane_valid(self))
1462 asprintf(&s, "<edlib.Pane FREED!!! %p>", self);
1464 asprintf(&s, "<edlib.Pane %p>", self->pane);
1465 ret = Py_BuildValue("s", s);
1470 static PyObject *doc_repr(Doc *self safe)
1474 if (!doc_valid(self))
1475 asprintf(&s, "<edlib.Doc FREED!!! %p>", self);
1477 asprintf(&s, "<edlib.Doc %p>", self->pane);
1478 ret = Py_BuildValue("s", s);
1483 static long pane_hash(Pane *p safe)
1485 return (long)p->pane;
1488 static PyObject *pane_cmp(Pane *p1 safe, Pane *p2 safe, int op)
1490 Py_RETURN_RICHCOMPARE(p1->pane, p2->pane, op);
1493 static PyGetSetDef pane_getseters[] = {
1495 (getter)pane_getnum, (setter)pane_setnum,
1496 "X offset in parent", "x" },
1498 (getter)pane_getnum, (setter)pane_setnum,
1499 "Y offset in parent", "y" },
1501 (getter)pane_getnum, (setter)pane_setnum,
1502 "Z offset in parent", "z" },
1504 (getter)pane_getnum, (setter)pane_setnum,
1505 "width of pane", "w" },
1507 (getter)pane_getnum, (setter)pane_setnum,
1508 "heigth of pane", "h" },
1510 (getter)pane_getnum, (setter)pane_setnum,
1511 "Cursor X offset in pane", "X" },
1513 (getter)pane_getnum, (setter)pane_setnum,
1514 "Cursor Y offset in pane", "Y" },
1516 (getter)pane_getnum, (setter)pane_setnum,
1517 "global Z offset", "Z" },
1519 (getter)pane_getpane, (setter)pane_nosetpane,
1520 "Parent pane", "p"},
1522 (getter)pane_getpane, (setter)pane_nosetpane,
1523 "Focal child", "f"},
1525 (getter)pane_getpane, (setter)pane_nosetpane,
1528 (getter)pane_getpane, (setter)pane_nosetpane,
1530 {NULL} /* Sentinel */
1533 static PyObject *Pane_get_item(Pane *self safe, PyObject *key safe)
1536 PyObject *t1 = NULL;
1538 if (!pane_valid(self))
1541 k = python_as_string(key, &t1);
1543 PyErr_SetString(PyExc_TypeError, "Key must be a string or unicode");
1546 v = pane_attr_get(self->pane, k);
1549 return Py_BuildValue("s", v);
1554 static int Pane_set_item(Pane *self safe, PyObject *key, PyObject *val)
1557 PyObject *t1 = NULL, *t2 = NULL;
1559 if (!pane_valid(self))
1562 k = python_as_string(key, &t1);
1564 PyErr_SetString(PyExc_TypeError, "Key must be a string or unicode");
1567 v = python_as_string(val, &t2);
1568 if (val != Py_None && !v) {
1569 PyErr_SetString(PyExc_TypeError, "value must be a string or unicode");
1573 attr_set_str(&self->pane->attrs, k, v);
1579 static PyMappingMethods pane_mapping = {
1581 .mp_subscript = (binaryfunc)Pane_get_item,
1582 .mp_ass_subscript = (objobjargproc)Pane_set_item,
1585 static PyTypeObject PaneType = {
1586 PyVarObject_HEAD_INIT(NULL, 0)
1587 .tp_name = "edlib.Pane",
1588 .tp_basicsize = sizeof(Pane),
1589 .tp_dealloc = (destructor)pane_dealloc,
1590 .tp_richcompare = (richcmpfunc)pane_cmp,
1591 .tp_repr = (reprfunc)pane_repr,
1592 .tp_as_mapping = &pane_mapping,
1593 .tp_hash = (hashfunc)pane_hash,
1594 .tp_call = (ternaryfunc)pane_direct_call,
1595 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1596 .tp_doc = "edlib panes",
1597 .tp_methods = pane_methods,
1598 .tp_getset = pane_getseters,
1599 .tp_init = (initproc)Pane_init,
1600 .tp_new = (newfunc)pane_new,
1603 static PyTypeObject PaneIterType = {
1604 PyVarObject_HEAD_INIT(NULL, 0)
1605 .tp_name = "edlib.PaneIter",
1606 .tp_basicsize = sizeof(PaneIter),
1607 .tp_dealloc = (destructor)paneiter_dealloc,
1608 .tp_flags = Py_TPFLAGS_DEFAULT,
1609 .tp_doc = "edlib pane iterator",
1610 .tp_iter = (getiterfunc)pane_this_iter,
1611 .tp_iternext = (iternextfunc)pane_iter_next,
1612 .tp_new = (newfunc)pane_iter_new,
1615 static PyObject *first_mark(Doc *self safe, PyObject *args)
1619 if (!doc_valid(self))
1622 m = mark_first(&self->doc);
1627 return Mark_Frommark(m);
1630 static PyObject *to_end(Doc *self safe, PyObject *args)
1636 if (!doc_valid(self))
1639 ret = PyArg_ParseTuple(args, "O!i", &MarkType, &mark, &end);
1640 if (ret <= 0 || !mark || !mark->mark) {
1641 PyErr_SetString(PyExc_TypeError, "Mark undefined or uninitialized");
1645 mark_to_end(self->pane, mark->mark, end);
1650 static PyMethodDef doc_methods[] = {
1651 {"first_mark", (PyCFunction)first_mark, METH_NOARGS,
1652 "first mark of document"},
1653 {"to_end", (PyCFunction)to_end, METH_VARARGS,
1654 "Move mark to one end of document"},
1658 static PyTypeObject DocType = {
1659 PyVarObject_HEAD_INIT(NULL, 0)
1660 .tp_name = "edlib.Doc",
1661 .tp_basicsize = sizeof(Doc),
1662 .tp_dealloc = (destructor)pane_dealloc,
1663 .tp_repr = (reprfunc)doc_repr,
1664 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1665 .tp_doc = "edlib document",
1666 .tp_methods = doc_methods,
1667 .tp_base = &PaneType,
1668 .tp_init = (initproc)Doc_init,
1669 .tp_new = (newfunc)Doc_new,
1672 static PyObject *mark_getoffset(Mark *m safe, void *x)
1675 if (m->mark == NULL) {
1676 PyErr_SetString(PyExc_TypeError, "Mark is NULL");
1679 d = m->mark->owner->data;
1680 if (d->refcnt == mark_refcnt)
1681 return PyLong_FromLong(m->mark->ref.o);
1682 return PyLong_FromLong(0);
1685 static int mark_setoffset(Mark *m safe, PyObject *v safe, void *x)
1690 if (m->mark == NULL) {
1691 PyErr_SetString(PyExc_TypeError, "Mark is NULL");
1694 val = PyLong_AsLong(v);
1695 if (val == -1 && PyErr_Occurred())
1697 d = m->mark->owner->data;
1698 if (d->refcnt == mark_refcnt)
1699 m->mark->ref.o = val;
1701 PyErr_SetString(PyExc_TypeError, "Setting offset on non-local mark");
1707 static PyObject *mark_getseq(Mark *m safe, void *x)
1709 if (m->mark == NULL) {
1710 PyErr_SetString(PyExc_TypeError, "Mark is NULL");
1713 return PyLong_FromLong(m->mark->seq);
1716 static int mark_nosetseq(Mark *m, PyObject *v, void *which)
1718 PyErr_SetString(PyExc_TypeError, "Cannot set mark seq number");
1722 static void mark_refcnt(struct mark *m safe, int inc)
1727 Py_INCREF(m->ref.c);
1731 Py_DECREF(m->ref.c);
1736 static PyObject *mark_getpos(Mark *m safe, void *x)
1739 if (m->mark == NULL) {
1740 PyErr_SetString(PyExc_TypeError, "Mark is NULL");
1743 d = m->mark->owner->data;
1744 if (d->refcnt == mark_refcnt && m->mark->ref.c) {
1745 Py_INCREF(m->mark->ref.c);
1746 return m->mark->ref.c;
1753 static int mark_setpos(Mark *m safe, PyObject *v, void *x)
1758 if (m->mark == NULL) {
1759 PyErr_SetString(PyExc_TypeError, "Mark is NULL");
1762 d = m->mark->owner->data;
1763 if (d->refcnt != mark_refcnt) {
1764 PyErr_SetString(PyExc_TypeError, "Cannot set ref for non-local mark");
1767 d->refcnt(m->mark, -1);
1768 /* If an adjacent mark has a ref.c with a matching value
1769 * use that instead, so that mark_same() works.
1771 if ((m2 = mark_next(m->mark)) != NULL &&
1772 ((struct doc *safe)m2->owner->data)->refcnt == mark_refcnt &&
1773 m2->ref.c != NULL &&
1774 PyObject_RichCompareBool(v, m2->ref.c, Py_EQ) == 1)
1775 m->mark->ref.c = m2->ref.c;
1776 else if ((m2 = mark_prev(m->mark)) != NULL &&
1777 ((struct doc *safe)m2->owner->data)->refcnt == mark_refcnt &&
1778 m2->ref.c != NULL &&
1779 PyObject_RichCompareBool(v, m2->ref.c, Py_EQ) == 1)
1780 m->mark->ref.c = m2->ref.c;
1783 d->refcnt(m->mark, 1);
1787 static PyObject *mark_getview(Mark *m safe, void *x)
1789 if (m->mark == NULL) {
1790 PyErr_SetString(PyExc_TypeError, "Mark is NULL");
1793 return PyLong_FromLong(m->mark->viewnum);
1796 static int mark_nosetview(Mark *m, PyObject *v, void *which)
1798 PyErr_SetString(PyExc_TypeError, "Cannot set mark viewnum");
1802 static PyObject *mark_compare(Mark *a safe, Mark *b safe, int op)
1804 if ((PyObject*)a == Py_None)
1805 Py_RETURN_RICHCOMPARE(0, 1, op);
1806 else if ((PyObject*)b == Py_None)
1807 Py_RETURN_RICHCOMPARE(1, 0, op);
1808 else if (PyObject_TypeCheck(a, &MarkType) == 0 ||
1809 PyObject_TypeCheck(b, &MarkType) == 0) {
1810 PyErr_SetString(PyExc_TypeError, "Mark compared with non-Mark");
1812 } else if (!a->mark || !b->mark)
1815 int cmp = a->mark->seq - b->mark->seq;
1816 if (mark_same(a->mark, b->mark))
1818 Py_RETURN_RICHCOMPARE(cmp, 0, op);
1822 static PyGetSetDef mark_getseters[] = {
1824 (getter)mark_getpos, (setter)mark_setpos,
1825 "Position ref", NULL},
1827 (getter)mark_getoffset, (setter)mark_setoffset,
1828 "Position offset", NULL},
1830 (getter)mark_getview, (setter)mark_nosetview,
1831 "Index for view list", NULL},
1833 (getter)mark_getseq, (setter)mark_nosetseq,
1834 "Sequence number of mark", NULL},
1835 {NULL} /* Sentinel */
1838 static Mark *mark_new(PyTypeObject *type safe, PyObject *args, PyObject *kwds)
1842 self = (Mark *)type->tp_alloc(type, 0);
1849 static int Mark_init(Mark *self safe, PyObject *args safe, PyObject *kwds)
1853 int view = MARK_UNGROUPED;
1855 static char *keywords[] = {"pane","view","orig", "owner", NULL};
1858 if (!PyTuple_Check(args) ||
1859 (PyTuple_GET_SIZE(args) == 0 && kwds == NULL))
1860 /* Internal Mark_Frommark call */
1863 ret = PyArg_ParseTupleAndKeywords(args, kwds, "|O!iO!O!", keywords,
1871 PyErr_SetString(PyExc_TypeError,
1872 "Only one of 'pane' and 'orig' may be set");
1875 if (!doc && !orig) {
1876 PyErr_SetString(PyExc_TypeError,
1877 "At least one of 'pane' and 'orig' must be set");
1880 if (doc && doc->pane) {
1881 struct pane *p = doc->pane;
1882 struct pane *op = owner ? owner->pane : NULL;
1885 self->mark = vmark_new(p, view, op);
1886 } else if (orig && orig->mark) {
1887 self->mark = mark_dup_view(orig->mark);
1890 PyErr_SetString(PyExc_TypeError, "Mark creation failed");
1893 if (self->mark->viewnum >= 0) {
1894 /* vmarks can use mdata and don't disappear until
1895 * explicitly released.
1897 self->mark->mtype = &MarkType;
1898 self->mark->mdata = (PyObject*)self;
1901 /* Other marks cannot use mdata and get freed when
1902 * the original PyObject is destroyed
1904 self->mark->mtype = (void*)self;
1909 static void mark_dealloc(Mark *self safe)
1911 if (self->mark && self->mark->mtype == (void*)self) {
1912 /* Python allocated this mark, so can free it. */
1913 struct mark *m = self->mark;
1919 do_free((PyObject*safe)self);
1922 static PyObject *Mark_to_mark(Mark *self safe, PyObject *args)
1925 int ret = PyArg_ParseTuple(args, "O!", &MarkType, &other);
1926 if (ret <= 0 || !other || !self->mark || !other->mark)
1928 mark_to_mark(self->mark, other->mark);
1934 static PyObject *Mark_to_mark_noref(Mark *self safe, PyObject *args)
1937 int ret = PyArg_ParseTuple(args, "O!", &MarkType, &other);
1938 if (ret <= 0 || !other || !self->mark || !other->mark)
1940 mark_to_mark_noref(self->mark, other->mark);
1946 static PyObject *Mark_clip(Mark *self safe, PyObject *args)
1948 Mark *start = NULL, *end = NULL;
1950 int ret = PyArg_ParseTuple(args, "O!O!|i", &MarkType, &start,
1951 &MarkType, &end, &tostart);
1953 if (ret > 0 && start && end && self->mark &&
1954 start->mark && end->mark)
1955 mark_clip(self->mark, start->mark, end->mark, !!tostart);
1961 static PyObject *Mark_step(Mark *self safe, PyObject *args)
1963 /* Convenience function to help implement doc:char */
1965 int ret = PyArg_ParseTuple(args, "i", &forward);
1967 if (ret > 0 && self->mark)
1968 mark_step(self->mark, forward);
1974 static PyObject *Mark_next(Mark *self safe, PyObject *args)
1978 PyErr_SetString(PyExc_TypeError, "Mark is NULL");
1981 if (self->mark->viewnum >= 0)
1982 next = vmark_next(self->mark);
1986 return Mark_Frommark(next);
1991 static PyObject *Mark_prev(Mark *self safe, PyObject *args)
1995 PyErr_SetString(PyExc_TypeError, "Mark is NULL");
1998 if (self->mark->viewnum >= 0)
1999 prev = vmark_prev(self->mark);
2003 return Mark_Frommark(prev);
2008 static PyObject *Mark_next_any(Mark *self safe, PyObject *args)
2012 PyErr_SetString(PyExc_TypeError, "Mark is NULL");
2015 next = mark_next(self->mark);
2017 return Mark_Frommark(next);
2022 static PyObject *Mark_prev_any(Mark *self safe, PyObject *args)
2026 PyErr_SetString(PyExc_TypeError, "Mark is NULL");
2029 prev = mark_prev(self->mark);
2031 return Mark_Frommark(prev);
2036 static PyObject *Mark_dup(Mark *self safe, PyObject *args)
2040 PyErr_SetString(PyExc_TypeError, "Mark is NULL");
2043 new = mark_dup(self->mark);
2045 Mark *ret = (Mark*)Mark_Frommark(new);
2046 /* We want this mark to be freed when the Mark
2049 new->mtype = (void*)ret;
2050 return (PyObject*)ret;
2057 static PyObject *Mark_release(Mark *self safe, PyObject *args)
2059 struct mark *m = self->mark;
2062 PyErr_SetString(PyExc_TypeError, "Mark has been freed");
2065 if (m->viewnum == MARK_UNGROUPED || m->viewnum == MARK_POINT) {
2066 PyErr_SetString(PyExc_TypeError,
2067 "Cannot release ungrouped marks or points");
2070 if (m->mtype == &MarkType) {
2071 /* We are dropping this mark - there cannot be any other ref */
2072 ASSERT(m->mdata == (PyObject*)self);
2084 static PyObject *Mark_ack(Mark *self safe, PyObject *args)
2086 struct mark *m = self->mark;
2089 PyErr_SetString(PyExc_TypeError, "Mark has been freed");
2097 static PyMethodDef mark_methods[] = {
2098 {"to_mark", (PyCFunction)Mark_to_mark, METH_VARARGS,
2099 "Move one mark to another"},
2100 {"to_mark_noref", (PyCFunction)Mark_to_mark_noref, METH_VARARGS,
2101 "Move one mark to another but don't update ref"},
2102 {"next", (PyCFunction)Mark_next, METH_NOARGS,
2104 {"prev", (PyCFunction)Mark_prev, METH_NOARGS,
2106 {"next_any", (PyCFunction)Mark_next_any, METH_NOARGS,
2108 {"prev_any", (PyCFunction)Mark_prev_any, METH_NOARGS,
2109 "previous any_mark"},
2110 {"dup", (PyCFunction)Mark_dup, METH_NOARGS,
2111 "duplicate a mark, as ungrouped"},
2112 {"clip", (PyCFunction)Mark_clip, METH_VARARGS,
2113 "If this mark is in range, move to end"},
2114 {"release", (PyCFunction)Mark_release, METH_NOARGS,
2115 "release a vmark so it can disappear"},
2116 {"ack", (PyCFunction)Mark_ack, METH_NOARGS,
2117 "acknowledge movement of a point - allow further notifications"},
2118 {"step", (PyCFunction)Mark_step, METH_VARARGS,
2119 "Move mark over any adjacent marks with same reference"},
2123 static PyObject *mark_get_item(Mark *self safe, PyObject *key safe)
2126 PyObject *t1 = NULL;
2129 PyErr_SetString(PyExc_TypeError, "Mark is NULL");
2132 k = python_as_string(key, &t1);
2134 PyErr_SetString(PyExc_TypeError, "Key must be a string or unicode");
2137 v = attr_find(self->mark->attrs, k);
2140 return Py_BuildValue("s", v);
2145 static int mark_set_item(Mark *self safe, PyObject *key safe, PyObject *val safe)
2148 PyObject *t1 = NULL, *t2 = NULL;
2150 PyErr_SetString(PyExc_TypeError, "Mark is NULL");
2153 k = python_as_string(key, &t1);
2155 PyErr_SetString(PyExc_TypeError, "Key must be a string or unicode");
2158 v = python_as_string(val, &t2);
2159 if (val != Py_None && !v) {
2160 PyErr_SetString(PyExc_TypeError, "value must be a string or unicode");
2164 attr_set_str(&self->mark->attrs, k, v);
2170 static PyObject *mark_repr(Mark *self safe)
2176 asprintf(&s, "<edlib.Mark seq=%d v=%d i=%d %p>",
2177 self->mark->seq, self->mark->viewnum,
2178 self->mark->ref.o, self->mark);
2180 asprintf(&s, "<edlib.Mark NULL %p>", self);
2181 ret = Py_BuildValue("s", s);
2186 static PyMappingMethods mark_mapping = {
2188 .mp_subscript = (binaryfunc)mark_get_item,
2189 .mp_ass_subscript = (objobjargproc)mark_set_item,
2192 static PyTypeObject MarkType = {
2193 PyVarObject_HEAD_INIT(NULL, 0)
2194 .tp_name = "edlib.Mark",
2195 .tp_basicsize = sizeof(Mark),
2196 .tp_dealloc = (destructor)mark_dealloc,
2197 .tp_as_mapping = &mark_mapping,
2198 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
2199 .tp_doc = "edlib marks",
2200 .tp_richcompare = (richcmpfunc)mark_compare,
2201 .tp_methods = mark_methods,
2202 .tp_getset = mark_getseters,
2203 .tp_init = (initproc)Mark_init,
2204 .tp_new = (newfunc)mark_new,
2205 .tp_repr = (reprfunc)mark_repr
2208 static void comm_dealloc(Comm *self safe)
2210 command_put(self->comm);
2211 do_free((PyObject*safe)self);
2214 static PyObject *comm_repr(Comm *self safe)
2220 asprintf(&s, "<edlib.Comm refcnt=%d %p>",
2221 self->comm->refcnt, self->comm);
2223 asprintf(&s, "<edlib.Comm NULL %p>", self);
2224 ret = Py_BuildValue("s", s);
2229 static PyObject *Comm_call(Comm *c safe, PyObject *args safe, PyObject *kwds)
2231 struct cmd_info ci = SAFE_CI;
2238 if (!get_cmd_info(&ci, args, kwds, &s1, &s2) ||
2239 !handle_ret(kwds, &ci, &pr)) {
2240 Py_XDECREF(s1); Py_XDECREF(s2);
2241 command_put(ci.comm2);
2245 rv = c->comm->func(&ci);
2246 Py_XDECREF(s1); Py_XDECREF(s2);
2247 command_put(ci.comm2);
2249 return choose_ret(rv, &pr);
2252 static PyObject *comm_cmp(Comm *c1 safe, Comm *c2 safe, int op)
2254 Py_RETURN_RICHCOMPARE(c1->comm, c2->comm, op);
2257 static Comm *comm_new(PyTypeObject *type safe, PyObject *args safe, PyObject *kwds)
2261 self = (Comm *)type->tp_alloc(type, 0);
2267 static PyTypeObject CommType = {
2268 PyVarObject_HEAD_INIT(NULL, 0)
2269 .tp_name = "edlib.Comm",
2270 .tp_basicsize = sizeof(Comm),
2271 .tp_dealloc = (destructor)comm_dealloc,
2272 .tp_richcompare = (richcmpfunc)comm_cmp,
2273 .tp_repr = (reprfunc)comm_repr,
2274 .tp_call = (ternaryfunc)Comm_call,
2275 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
2276 .tp_doc = "edlib command",
2277 .tp_new = (newfunc)comm_new,
2280 static void python_free_command(struct command *c safe)
2282 struct python_command *pc = container_of(c, struct python_command, c);
2285 Py_DECREF(pc->callable);
2290 /* The 'call' function takes liberties with arg passing.
2291 * Positional args must start with the key, and then are handled based on
2292 * there type. They can be panes, strigns, ints, pairs, marks, commands.
2293 * Panes are assigned to focus, then home.
2294 * Strings (after the key) are assigned to 'str' then 'str2'.
2296 * Ints are assigned to num then num2
2297 * Pairs (must be of ints) are assigned to x,y then hx,hy.
2298 * Marks are assigned to mark then mark2
2299 * A command is assigned to comm2 (comm is set automatically)
2300 * kwd arguments can also be used, currently
2301 * key, home, focus, xy, hxy, str, str2, mark, mark2, comm2.
2302 * A 'None' arg is ignored - probably a mark or string or something. Just use NULL
2304 static bool get_cmd_info(struct cmd_info *ci safe, PyObject *args safe, PyObject *kwds,
2305 PyObject **s1 safe, PyObject **s2 safe)
2310 int num_set = 0, num2_set = 0;
2315 if (!PyTuple_Check(args))
2317 argc = PyTuple_GET_SIZE(args);
2319 /* First positional arg must be the key */
2320 a = PyTuple_GetItem(args, 0);
2321 if (!PyUnicode_Check(a)) {
2322 PyErr_SetString(PyExc_TypeError, "First arg must be key");
2325 ci->key = safe_cast PyUnicode_AsUTF8(a);
2327 for (i = 1; i < argc; i++) {
2328 a = PyTuple_GetItem(args, i);
2330 /* quietly ignore */;
2331 else if (PyObject_TypeCheck(a, &PaneType)) {
2332 if ((void*)ci->home == NULL)
2333 ci->home = safe_cast ((Pane*)a)->pane;
2334 else if ((void*)ci->focus == NULL)
2335 ci->focus = safe_cast ((Pane*)a)->pane;
2337 PyErr_SetString(PyExc_TypeError, "Only 2 Pane args permitted");
2340 } else if (PyObject_TypeCheck(a, &MarkType)) {
2341 if (ci->mark == NULL)
2342 ci->mark = ((Mark*)a)->mark;
2343 else if (ci->mark2 == NULL)
2344 ci->mark2 = ((Mark*)a)->mark;
2346 PyErr_SetString(PyExc_TypeError, "Only 2 Mark args permitted");
2349 } else if (PyUnicode_Check(a)) {
2352 if (ci->str && ci->str2) {
2353 PyErr_SetString(PyExc_TypeError, "Only 3 String args permitted");
2356 str = python_as_string(a, &s);
2363 if (ci->str == NULL)
2367 } else if (PyLong_Check(a)) {
2369 ci->num = PyLong_AsLong(a);
2371 } else if (!num2_set) {
2372 ci->num2 = PyLong_AsLong(a);
2375 PyErr_SetString(PyExc_TypeError, "Only 2 Number args permitted");
2378 } else if (PyTuple_Check(a)) {
2379 int n = PyTuple_GET_SIZE(a);
2382 PyErr_SetString(PyExc_TypeError, "Only 2-element tuples permitted");
2385 n1 = PyTuple_GetItem(a, 0);
2386 n2 = PyTuple_GetItem(a, 1);
2387 if (!PyLong_Check(n1) || !PyLong_Check(n2)) {
2388 PyErr_SetString(PyExc_TypeError, "Only tuples of integers permitted");
2392 ci->x = PyLong_AsLong(n1);
2393 ci->y = PyLong_AsLong(n2);
2396 PyErr_SetString(PyExc_TypeError, "Only one tuple permitted");
2399 } else if (PyObject_TypeCheck(a, &CommType)) {
2401 if (ci->comm2 == NULL && c->comm) {
2402 ci->comm2 = command_get(c->comm);
2404 PyErr_SetString(PyExc_TypeError, "Only one callable permitted");
2407 } else if (PyCallable_Check(a)) {
2408 struct python_command *pc = export_callable(a);
2410 if (ci->comm2 == NULL)
2413 command_put(&pc->c);
2414 PyErr_SetString(PyExc_TypeError, "Only one callable permitted");
2418 PyErr_Format(PyExc_TypeError, "Unsupported arg type %d", i);
2422 if (kwds && PyDict_Check(kwds)) {
2423 a = PyDict_GetItemString(kwds, "str");
2424 if (a && a != Py_None) {
2425 if (*s1 || ci->str) {
2426 PyErr_SetString(PyExc_TypeError,
2427 "'str' given with other strings");
2430 if (!PyUnicode_Check(a)) {
2431 PyErr_SetString(PyExc_TypeError,
2432 "'str' must be string or unicode");
2435 ci->str = python_as_string(a, s1);
2437 a = PyDict_GetItemString(kwds, "str2");
2438 if (a && a != Py_None) {
2439 if (*s2 || ci->str2) {
2440 PyErr_SetString(PyExc_TypeError,
2441 "'str2' given with 2 strings");
2444 if (!PyUnicode_Check(a)) {
2445 PyErr_SetString(PyExc_TypeError,
2446 "'str2' must be string or unicode");
2449 ci->str2 = python_as_string(a, s2);
2451 a = PyDict_GetItemString(kwds, "mark");
2452 if (a && a != Py_None) {
2454 PyErr_SetString(PyExc_TypeError,
2455 "'mark' given with other marks");
2458 if (!PyObject_TypeCheck(a, &MarkType)) {
2459 PyErr_SetString(PyExc_TypeError,
2460 "'mark' must be an edlib.Mark");
2463 ci->mark = ((Mark*)a)->mark;
2465 a = PyDict_GetItemString(kwds, "mark2");
2466 if (a && a != Py_None) {
2468 PyErr_SetString(PyExc_TypeError,
2469 "'mark2' given with 2 other marks");
2472 if (!PyObject_TypeCheck(a, &MarkType)) {
2473 PyErr_SetString(PyExc_TypeError,
2474 "'mark2' must be an edlib.Mark");
2477 ci->mark2 = ((Mark*)a)->mark;
2479 a = PyDict_GetItemString(kwds, "num");
2482 PyErr_SetString(PyExc_TypeError,
2483 "'num' given with other numbers");
2486 if (!PyLong_Check(a)) {
2487 PyErr_SetString(PyExc_TypeError,
2488 "'num' must be an integer");
2491 ci->num = PyLong_AsLong(a);
2494 a = PyDict_GetItemString(kwds, "num2");
2497 PyErr_SetString(PyExc_TypeError,
2498 "'num2' given with 2 other numbers");
2501 if (!PyLong_Check(a)) {
2502 PyErr_SetString(PyExc_TypeError,
2503 "'num2' must be an integer");
2506 ci->num2 = PyLong_AsLong(a);
2509 a = PyDict_GetItemString(kwds, "focus");
2510 if (a && a != Py_None) {
2512 if ((void*)ci->focus) {
2513 PyErr_SetString(PyExc_TypeError,
2514 "'focus' given with other pane");
2517 if (!PyObject_TypeCheck(a, &PaneType)) {
2518 PyErr_SetString(PyExc_TypeError,
2519 "'focus' must be a pane");
2524 ci->focus = p->pane;
2526 PyErr_SetString(PyExc_TypeError, "focus value invalid");
2530 a = PyDict_GetItemString(kwds, "xy");
2531 if (a && a != Py_None) {
2534 PyErr_SetString(PyExc_TypeError,
2535 "'xy' given with other tuple");
2538 if (!PyTuple_Check(a) || PyTuple_GET_SIZE(a) != 2) {
2539 PyErr_SetString(PyExc_TypeError,
2540 "'xy' must be a tuple of 2 integers");
2543 n1 = PyTuple_GetItem(a, 0);
2544 n2 = PyTuple_GetItem(a, 1);
2545 if (!PyLong_Check(n1) || !PyLong_Check(n2)) {
2546 PyErr_SetString(PyExc_TypeError, "Only tuples of integers permitted");
2549 ci->x = PyLong_AsLong(n1);
2550 ci->y = PyLong_AsLong(n2);
2553 a = PyDict_GetItemString(kwds, "comm2");
2554 if (a && a != Py_None) {
2556 PyErr_SetString(PyExc_TypeError,
2557 "'comm2' given with other command");
2560 if (PyObject_TypeCheck(a, &CommType)) {
2563 ci->comm2 = command_get(c->comm);
2565 PyErr_SetString(PyExc_TypeError, "comm2 value invalid");
2568 } else if (PyCallable_Check(a)) {
2569 struct python_command *pc = export_callable(a);
2573 PyErr_SetString(PyExc_TypeError,
2574 "'comm2' must be a callable");
2579 if (!(void*)ci->key) {
2580 PyErr_SetString(PyExc_TypeError, "No key specified");
2583 if (!(void*)ci->home) {
2584 PyErr_SetString(PyExc_TypeError, "No pane specified");
2587 if (!(void*)ci->focus)
2588 ci->focus = ci->home;
2593 static PyObject *py_time_start(PyObject *self, PyObject *args)
2596 int ret = PyArg_ParseTuple(args, "i", &type);
2606 static PyObject *py_time_stop(PyObject *self, PyObject *args)
2609 int ret = PyArg_ParseTuple(args, "i", &type);
2619 static PyObject *py_LOG(PyObject *self, PyObject *args)
2621 int argc = PySequence_Length(args);
2626 for (i = 0; i < argc; i++) {
2627 PyObject *o = PySequence_GetItem(args, i);
2628 PyObject *s, *tofree = NULL;
2634 s = PyObject_Str(o);
2638 str = python_as_string(s, &tofree);
2639 slen = str ? strlen(str) : 0;
2640 if (str && slen < sizeof(buf) - l - 2) {
2656 static PyMethodDef edlib_methods[] = {
2657 {"time_start", py_time_start, METH_VARARGS,
2658 "Record start time"},
2659 {"time_stop", py_time_stop, METH_VARARGS,
2660 "Record stop time"},
2661 {"LOG", py_LOG, METH_VARARGS,
2662 "Generate log message"},
2663 {NULL, NULL, 0, NULL}
2666 /* This must be visible when the module is loaded so it
2667 * cannot be static. spares doesn't like variables that are
2668 * neither extern nor static. So mark it extern
2670 extern char *edlib_module_path;
2671 char *edlib_module_path;
2673 static struct PyModuleDef edlib_mod = {
2674 PyModuleDef_HEAD_INIT,
2676 .m_doc = "edlib - one more editor is never enough.",
2677 .m_methods = edlib_methods,
2680 void edlib_init(struct pane *ed safe)
2683 wchar_t *argv[1]= { NULL };
2685 if (edlib_module_path)
2686 module_dir = strdup(edlib_module_path);
2690 /* This cast is for sparse, which doesn't seem to cope with L".."
2693 Py_SetProgramName((wchar_t*)L"edlib");
2695 PySys_SetArgv(0, argv);
2697 PaneType.tp_new = PyType_GenericNew;
2698 PaneIterType.tp_new = PyType_GenericNew;
2699 DocType.tp_new = PyType_GenericNew;
2700 MarkType.tp_new = PyType_GenericNew;
2701 CommType.tp_new = PyType_GenericNew;
2702 if (PyType_Ready(&PaneType) < 0 ||
2703 PyType_Ready(&PaneIterType) < 0 ||
2704 PyType_Ready(&DocType) < 0 ||
2705 PyType_Ready(&MarkType) < 0 ||
2706 PyType_Ready(&CommType) < 0)
2709 m = PyModule_Create(&edlib_mod);
2714 PyModule_AddObject(m, "Pane", (PyObject *)&PaneType);
2715 PyModule_AddObject(m, "PaneIter", (PyObject *)&PaneIterType);
2716 PyModule_AddObject(m, "Mark", (PyObject *)&MarkType);
2717 PyModule_AddObject(m, "Comm", (PyObject *)&CommType);
2718 PyModule_AddObject(m, "Doc", (PyObject *)&DocType);
2719 PyModule_AddIntMacro(m, DAMAGED_CHILD);
2720 PyModule_AddIntMacro(m, DAMAGED_SIZE);
2721 PyModule_AddIntMacro(m, DAMAGED_VIEW);
2722 PyModule_AddIntMacro(m, DAMAGED_REFRESH);
2723 PyModule_AddIntMacro(m, DAMAGED_POSTORDER);
2724 PyModule_AddIntMacro(m, DAMAGED_CLOSED);
2725 PyModule_AddIntMacro(m, Efallthrough);
2726 PyModule_AddIntMacro(m, Enoarg);
2727 PyModule_AddIntMacro(m, Einval);
2728 PyModule_AddIntMacro(m, Efalse);
2729 PyModule_AddIntMacro(m, Efail);
2730 PyModule_AddIntMacro(m, Enosup);
2731 PyModule_AddIntMacro(m, Efail);
2732 PyModule_AddIntMacro(m, NO_NUMERIC);
2734 PyModule_AddIntMacro(m, TIME_KEY);
2735 PyModule_AddIntMacro(m, TIME_WINDOW);
2736 PyModule_AddIntMacro(m, TIME_READ);
2737 PyModule_AddIntMacro(m, TIME_SIG);
2738 PyModule_AddIntMacro(m, TIME_TIMER);
2739 PyModule_AddIntMacro(m, TIME_IDLE);
2740 PyModule_AddIntMacro(m, TIME_REFRESH);
2742 PyModule_AddIntMacro(m, RXL_ANCHORED);
2743 PyModule_AddIntMacro(m, RXL_BACKTRACK);
2745 PyModule_AddIntMacro(m, MARK_UNGROUPED);
2746 PyModule_AddIntMacro(m, MARK_POINT);
2748 PyModule_AddIntConstant(m, "WEOF", 0x3FFFFF);
2749 call_comm("global-set-command", ed, &python_load, 0, NULL, "python-load");
2750 call_comm("global-set-command", ed, &python_load_module,
2751 0, NULL, "global-load-modules:python");
2753 Edlib_CommandFailed = PyErr_NewException("edlib.commandfailed", NULL, NULL);
2754 Py_INCREF(Edlib_CommandFailed);
2755 PyModule_AddObject(m, "commandfailed", Edlib_CommandFailed);