Created
January 5, 2013 04:29
-
-
Save nemith/4459752 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <Python.h> | |
| /* libedit */ | |
| #include <histedit.h> | |
| #include <structmember.h> | |
| /* Prompt generating functions added via EL_PROMPT, EL_RPROMPT */ | |
| //typedef char *(*pfunc_t)(EditLine *); | |
| /* User functions added via EL_ADDFN */ | |
| typedef char (*ufunc_t)(EditLine *e, int ch); | |
| char uf_wrapper(EditLine*, int, int); | |
| #define MAX_USER_FUNC 32 | |
| #define UF(x) \ | |
| static char uf##x(EditLine *e, int ch) { return uf_wrapper(e, ch, x); } | |
| #define UF_NAME(x) uf##x | |
| /* Define a unqiue function to call for custom user added functions added via | |
| the EL_ADDFN method. This count need to match MAX_USER_FUNC. */ | |
| UF(0) UF(1) UF(2) UF(3) UF(4) UF(5) UF(6) UF(7) | |
| UF(8) UF(9) UF(10) UF(11) UF(12) UF(13) UF(14) UF(15) | |
| UF(16) UF(17) UF(18) UF(19) UF(20) UF(21) UF(22) UF(23) | |
| UF(24) UF(25) UF(26) UF(27) UF(28) UF(29) UF(30) UF(31) | |
| static ufunc_t uf_tbl[MAX_USER_FUNC] = { | |
| UF_NAME(0), UF_NAME(1), UF_NAME(2), UF_NAME(3), UF_NAME(4), UF_NAME(5), UF_NAME(6), UF_NAME(7), | |
| UF_NAME(8), UF_NAME(9), UF_NAME(10), UF_NAME(11), UF_NAME(12), UF_NAME(13), UF_NAME(14), UF_NAME(15), | |
| UF_NAME(16), UF_NAME(17), UF_NAME(18), UF_NAME(19), UF_NAME(20), UF_NAME(21), UF_NAME(22), UF_NAME(23), | |
| UF_NAME(24), UF_NAME(25), UF_NAME(26), UF_NAME(27), UF_NAME(28), UF_NAME(29), UF_NAME(30), UF_NAME(31) | |
| }; | |
| typedef struct { | |
| PyObject *method; | |
| char *name; | |
| } um_info_t; | |
| typedef struct { | |
| PyObject *prompt_object; /* callable or object as a string */ | |
| PyObject *rprompt_object; /* callable or object as a string */ | |
| um_info_t *user_methods[MAX_USER_FUNC]; | |
| } sess_data_t; | |
| typedef struct { | |
| PyObject_HEAD | |
| EditLine *el; /* EditLine wrapped object */ | |
| } editline_EditLine; | |
| char *call_prompt_method(EditLine *el, PyObject **prompt_object) { | |
| PyObject *r = NULL; | |
| char *result = NULL; | |
| if (*prompt_object != NULL) { | |
| if (PyCallable_Check(*prompt_object)) { | |
| r = PyObject_CallObject(*prompt_object, NULL); | |
| if (r == NULL) { | |
| /* HACK: Force an enter to return to python enviroment to raise the | |
| error */ | |
| el_push(el, "\n"); | |
| return ""; | |
| } | |
| result = PyBytes_AsString(PyUnicode_AsASCIIString(r)); | |
| } | |
| } | |
| Py_DECREF(r); | |
| return result; | |
| } | |
| char *prompt(EditLine *el) { | |
| sess_data_t *sd; | |
| if (el_get(el, EL_CLIENTDATA, &sd) == 0) { | |
| return call_prompt_method(el, &sd->prompt_object); | |
| } | |
| /* XXX: Raise error here */ | |
| return ""; | |
| } | |
| char *rprompt(EditLine *el) { | |
| sess_data_t *sd; | |
| if (el_get(el, EL_CLIENTDATA, &sd) == 0) { | |
| return call_prompt_method(el, &sd->rprompt_object); | |
| } | |
| /* XXX: Raise error here */ | |
| return ""; | |
| } | |
| char uf_wrapper(EditLine *el, int ch, int idx) { | |
| sess_data_t *sd; | |
| PyObject *result = NULL; | |
| if (el_get(el, EL_CLIENTDATA, &sd) == 0) { | |
| um_info_t *um_info = sd->user_methods[idx]; | |
| if (um_info && um_info->method) { | |
| if (PyCallable_Check(um_info->method)) { | |
| result = PyObject_CallObject(um_info->method, NULL); | |
| } | |
| if (result == Py_None) | |
| return CC_NORM; | |
| return PyLong_AsLong(result); | |
| } | |
| } | |
| return CC_FATAL; | |
| } | |
| static void EditLine_dealloc(editline_EditLine* self) { | |
| el_end(self->el); | |
| Py_TYPE(self)->tp_free((PyObject*)self); | |
| } | |
| static int EditLine_init(editline_EditLine *self, PyObject *args, PyObject *kwds) { | |
| self->el = el_init("prog", stdin, stdout, stderr); | |
| sess_data_t *sd; | |
| sd = malloc(sizeof(sess_data_t)); | |
| sd->prompt_object = NULL; | |
| sd->rprompt_object = NULL; | |
| el_set(self->el, EL_CLIENTDATA, sd); | |
| return 1; | |
| } | |
| static PyMemberDef EditLine_members[] = { | |
| // {"prompt", T_OBJECT_EX, offsetof(editline_EditLine, prompt), 0 | |
| // "prompt method or string"}, | |
| {NULL} /* Sentinel */ | |
| }; | |
| static PyObject * | |
| set_prompt_method(PyObject **prompt_object, PyObject *args) { | |
| PyObject *temp; | |
| if (!PyArg_ParseTuple(args, "O", &temp)) | |
| return NULL; | |
| /* Since we'll call this from C later lets try to run it once and | |
| see if there are errors now. Not 100% but may get some of the | |
| easy errors */ | |
| if (PyObject_CallObject(temp, NULL) == NULL) | |
| return NULL; | |
| Py_XINCREF(temp); | |
| Py_XDECREF(*prompt_object); | |
| *prompt_object = temp; | |
| Py_RETURN_NONE; | |
| } | |
| static PyObject * | |
| EditLine_set_prompt(editline_EditLine *self, PyObject *args, PyObject *kwds) { | |
| sess_data_t *sd; | |
| el_get(self->el, EL_CLIENTDATA, &sd); | |
| el_set(self->el, EL_PROMPT, &prompt); | |
| return set_prompt_method(&sd->prompt_object, args); | |
| } | |
| static PyObject * | |
| EditLine_set_rprompt(editline_EditLine *self, PyObject *args, PyObject *kwds) { | |
| sess_data_t *sd; | |
| el_get(self->el, EL_CLIENTDATA, &sd); | |
| el_set(self->el, EL_RPROMPT, &rprompt); | |
| return set_prompt_method(&sd->rprompt_object, args); | |
| } | |
| static int | |
| EditLine_refresh(editline_EditLine *self, PyObject *args) { | |
| int ret; | |
| ret = el_set(self->el, EL_REFRESH); | |
| return ret; | |
| } | |
| static PyObject * | |
| EditLine_set_editor(editline_EditLine *self, PyObject *args, PyObject *kwds) { | |
| char *editor_mode; | |
| if (!PyArg_ParseTuple(args, "s", &editor_mode)) | |
| return NULL; | |
| el_set(self->el, EL_EDITOR, editor_mode); | |
| Py_RETURN_NONE; | |
| } | |
| static PyObject * | |
| EditLine_set_terminal(editline_EditLine *self, PyObject *args, PyObject *kwds) { | |
| char *terminal_mode; | |
| if (!PyArg_ParseTuple(args, "s", &terminal_mode)) | |
| return NULL; | |
| el_set(self->el, EL_TERMINAL, *terminal_mode); | |
| Py_RETURN_NONE; | |
| } | |
| /* EL_SIGNAL */ | |
| /* EL_BIND */ | |
| static PyObject * | |
| EditLine_bindkey(editline_EditLine *self, PyObject *args, PyObject *kwds) { | |
| char *bound_key, *func_name = NULL; | |
| if (!PyArg_ParseTuple(args, "ss", &bound_key, &func_name)) | |
| return NULL; | |
| /* if (PyCallable_Check(method)) { | |
| if (!method_name) | |
| sprintf(method_name, "%s_%s", PyEval_GetFuncName(method), PyLong_FromVoidPtr(method)); | |
| for (int i = 0, i < MAX_USER_FUNC; i++) { | |
| } | |
| el_set(self->el, EL_ADDFN, func_name, PyEval_GetFuncDesc(cmd), bound); | |
| } */ | |
| el_set(self->el, EL_BIND, bound_key, func_name, NULL); | |
| Py_RETURN_NONE; | |
| } | |
| static PyObject * | |
| EditLine_addfn(editline_EditLine *self, PyObject *args, PyObject *kwds) { | |
| char *func_name = NULL; | |
| char *func_help = ""; | |
| PyObject *method; | |
| if (!PyArg_ParseTuple(args, "sO|s", &func_name, &method, &func_help)) | |
| return NULL; | |
| sess_data_t *sd; | |
| if (el_get(self->el, EL_CLIENTDATA, &sd) != 0) | |
| return NULL; | |
| if (PyCallable_Check(method)) { | |
| for (int volatile i = 0; i < MAX_USER_FUNC; i++) { | |
| if (sd->user_methods[i] == NULL) { | |
| if ((sd->user_methods[i] = malloc(sizeof(um_info_t))) == 0) | |
| return PyErr_NoMemory(); | |
| sd->user_methods[i]->method = method; | |
| sd->user_methods[i]->name = func_name; | |
| el_set(self->el, EL_ADDFN, func_name, func_help, uf_tbl[i]); | |
| break; | |
| } | |
| } | |
| } | |
| Py_RETURN_NONE; | |
| } | |
| static PyObject * | |
| EditLine_gets(editline_EditLine *self, PyObject *args, PyObject *kwds) { | |
| int count; | |
| const char *line; | |
| line = el_gets(self->el, &count); | |
| if (count > 0 ) | |
| return PyUnicode_FromFormat("%s", line); | |
| Py_RETURN_NONE; | |
| } | |
| static PyMethodDef EditLine_methods[] = { | |
| {"gets", (PyCFunction)EditLine_gets, METH_NOARGS, | |
| "Read a line from the tty." | |
| }, | |
| {"set_prompt", (PyCFunction)EditLine_set_prompt, METH_VARARGS, | |
| "Set the prompt to a string or function that return a string." | |
| }, | |
| {"refresh", (PyCFunction)EditLine_refresh, METH_NOARGS, | |
| "Re-display the current line on the next terminal line." | |
| }, | |
| {"set_rprompt", (PyCFunction)EditLine_set_rprompt, METH_VARARGS, | |
| "Set the right prompt to a string or function that return a string." | |
| }, | |
| {"set_editor", (PyCFunction)EditLine_set_editor, METH_VARARGS, | |
| "Set editing mode to mode, which must be one of 'emacs' or 'vi'." | |
| }, | |
| {"set_terminal", (PyCFunction)EditLine_set_terminal, METH_VARARGS, | |
| "Define terminal type of the tty to be type, or to TERM if type is None." | |
| }, | |
| {"bindkey", (PyCFunction)EditLine_bindkey, METH_VARARGS, | |
| "Bind a key to a function." | |
| }, | |
| {"addfn", (PyCFunction)EditLine_addfn, METH_VARARGS, | |
| "Add a user defined function." | |
| }, | |
| {NULL} /* Sentinel */ | |
| }; | |
| static PyTypeObject editline_EditLineType = { | |
| PyVarObject_HEAD_INIT(NULL, 0) | |
| "editline.EditLine", /* tp_name */ | |
| sizeof(editline_EditLine), /* tp_basicsize */ | |
| 0, /* tp_itemsize */ | |
| (destructor)EditLine_dealloc, /* 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, /* tp_flags */ | |
| "EditLine objects", /* tp_doc */ | |
| 0, /* tp_traverse */ | |
| 0, /* tp_clear */ | |
| 0, /* tp_richcompare */ | |
| 0, /* tp_weaklistoffset */ | |
| 0, /* tp_iter */ | |
| 0, /* tp_iternext */ | |
| EditLine_methods, /* tp_methods */ | |
| EditLine_members, /* tp_members */ | |
| 0, /* tp_getset */ | |
| 0, /* tp_base */ | |
| 0, /* tp_dict */ | |
| 0, /* tp_descr_get */ | |
| 0, /* tp_descr_set */ | |
| 0, /* tp_dictoffset */ | |
| (initproc)EditLine_init, /* tp_init */ | |
| 0, /* tp_alloc */ | |
| PyType_GenericNew, /* tp_new */ | |
| }; | |
| static PyModuleDef editlinemodule = { | |
| PyModuleDef_HEAD_INIT, | |
| "editline", | |
| "Example module that creates an extension type.", | |
| -1, | |
| NULL, NULL, NULL, NULL, NULL | |
| }; | |
| PyMODINIT_FUNC | |
| PyInit_editline(void) | |
| { | |
| PyObject* m; | |
| editline_EditLineType.tp_new = PyType_GenericNew; | |
| if (PyType_Ready(&editline_EditLineType) < 0) | |
| return NULL; | |
| m = PyModule_Create(&editlinemodule); | |
| if (m == NULL) | |
| return NULL; | |
| Py_INCREF(&editline_EditLineType); | |
| PyModule_AddObject(m, "EditLine", (PyObject *)&editline_EditLineType); | |
| // Custom function return values | |
| PyModule_AddIntConstant(m, "CC_NORM", CC_NORM); | |
| PyModule_AddIntConstant(m, "CC_NEWLINE", CC_NEWLINE); | |
| PyModule_AddIntConstant(m, "CC_EOF", CC_EOF); | |
| PyModule_AddIntConstant(m, "CC_ARGHACK", CC_ARGHACK); | |
| PyModule_AddIntConstant(m, "CC_REFRESH", CC_REFRESH); | |
| PyModule_AddIntConstant(m, "CC_REFRESH_BEEP", CC_REFRESH_BEEP); | |
| PyModule_AddIntConstant(m, "CC_CURSOR", CC_CURSOR); | |
| PyModule_AddIntConstant(m, "CC_REDISPLAY", CC_REDISPLAY); | |
| PyModule_AddIntConstant(m, "CC_ERROR", CC_ERROR); | |
| PyModule_AddIntConstant(m, "CC_FATAL", CC_FATAL); | |
| return m; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| homestar:editline bbennett$ python3 test.py | |
| [email protected]> | |
| % You typed '' | |
| [email protected]> | |
| % You typed '' | |
| [email protected]> Hi mom | |
| % You typed 'Hi mom' | |
| [email protected]> | |
| You hit the question marks! | |
| quit Quit this shit yo | |
| [email protected]> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import editline | |
| import os | |
| import pwd | |
| import socket | |
| def get_username(): | |
| return pwd.getpwuid(os.getuid())[0] | |
| def prompt(): | |
| return "%s@%s> " % (get_username(), socket.gethostname()) | |
| def help(): | |
| print("\nYou hit the question marks!") | |
| print("\tquit\tQuit this shit yo") | |
| return editline.CC_REDISPLAY | |
| el = editline.EditLine() | |
| el.set_prompt(prompt) | |
| el.addfn('help', help) | |
| el.bindkey('?', 'help') | |
| while (1): | |
| line = el.gets(); | |
| print("%% You typed '%s'" % line.strip()) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment