diff options
Diffstat (limited to 'Modules/readline.c')
-rw-r--r-- | Modules/readline.c | 151 |
1 files changed, 127 insertions, 24 deletions
diff --git a/Modules/readline.c b/Modules/readline.c index 6469d27..49839c4 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -158,12 +158,80 @@ get_history_length(PyObject *self, PyObject *args) return Py_BuildValue("i", history_length); } +/* Generic hook function setter */ +static PyObject * +set_hook(const char * funcname, PyObject **hook_var, PyThreadState **tstate, PyObject *args) +{ + PyObject *function = Py_None; + char buf[80]; + sprintf(buf, "|O:set_%s", funcname); + if (!PyArg_ParseTuple(args, buf, &function)) + return NULL; + if (function == Py_None) { + Py_XDECREF(*hook_var); + *hook_var = NULL; + *tstate = NULL; + } + else if (PyCallable_Check(function)) { + PyObject *tmp = *hook_var; + Py_INCREF(function); + *hook_var = function; + Py_XDECREF(tmp); + *tstate = PyThreadState_Get(); + } + else { + sprintf(buf, "set_%s(func): argument not callable", funcname); + PyErr_SetString(PyExc_TypeError, buf); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +/* Exported functions to specify hook functions in Python */ + +static PyObject *startup_hook = NULL; +static PyThreadState *startup_hook_tstate = NULL; + +#ifdef HAVE_RL_PRE_INPUT_HOOK +static PyObject *pre_input_hook = NULL; +static PyThreadState *pre_input_hook_tstate = NULL; +#endif + +static PyObject * +set_startup_hook(PyObject *self, PyObject *args) +{ + return set_hook("startup_hook", &startup_hook, &startup_hook_tstate, args); +} + +static char doc_set_startup_hook[] = "\ +set_startup_hook([function]) -> None\n\ +Set or remove the startup_hook function.\n\ +The function is called with no arguments just\n\ +before readline prints the first prompt.\n\ +"; + +#ifdef HAVE_RL_PRE_INPUT_HOOK +static PyObject * +set_pre_input_hook(PyObject *self, PyObject *args) +{ + return set_hook("pre_input_hook", &pre_input_hook, &pre_input_hook_tstate, args); +} + +static char doc_set_pre_input_hook[] = "\ +set_pre_input_hook([function]) -> None\n\ +Set or remove the pre_input_hook function.\n\ +The function is called with no arguments after the first prompt\n\ +has been printed and just before readline starts reading input\n\ +characters.\n\ +"; +#endif /* Exported function to specify a word completer in Python */ static PyObject *completer = NULL; -static PyThreadState *tstate = NULL; +static PyThreadState *completer_tstate = NULL; static PyObject *begidx = NULL; static PyObject *endidx = NULL; @@ -238,28 +306,7 @@ get the readline word delimiters for tab-completion"; static PyObject * set_completer(PyObject *self, PyObject *args) { - PyObject *function = Py_None; - if (!PyArg_ParseTuple(args, "|O:set_completer", &function)) - return NULL; - if (function == Py_None) { - Py_XDECREF(completer); - completer = NULL; - tstate = NULL; - } - else if (PyCallable_Check(function)) { - PyObject *tmp = completer; - Py_INCREF(function); - completer = function; - Py_XDECREF(tmp); - tstate = PyThreadState_Get(); - } - else { - PyErr_SetString(PyExc_TypeError, - "set_completer(func): argument not callable"); - return NULL; - } - Py_INCREF(Py_None); - return Py_None; + return set_hook("completer", &completer, &completer_tstate, args); } static char doc_set_completer[] = "\ @@ -330,9 +377,60 @@ static struct PyMethodDef readline_methods[] = METH_VARARGS, doc_set_completer_delims}, {"get_completer_delims", get_completer_delims, METH_OLDARGS, doc_get_completer_delims}, + + {"set_startup_hook", set_startup_hook, METH_VARARGS, doc_set_startup_hook}, +#ifdef HAVE_RL_PRE_INPUT_HOOK + {"set_pre_input_hook", set_pre_input_hook, METH_VARARGS, doc_set_pre_input_hook}, +#endif {0, 0} }; +/* C function to call the Python hooks. */ + +static int +on_hook(PyObject *func, PyThreadState *tstate) +{ + int result = 0; + if (func != NULL) { + PyObject *r; + PyThreadState *save_tstate; + /* Note that readline is called with the interpreter + lock released! */ + save_tstate = PyThreadState_Swap(NULL); + PyEval_RestoreThread(tstate); + r = PyObject_CallFunction(func, NULL); + if (r == NULL) + goto error; + if (r == Py_None) + result = 0; + else + result = PyInt_AsLong(r); + Py_DECREF(r); + goto done; + error: + PyErr_Clear(); + Py_XDECREF(r); + done: + PyEval_SaveThread(); + PyThreadState_Swap(save_tstate); + } + return result; +} + +static int +on_startup_hook(void) +{ + return on_hook(startup_hook, startup_hook_tstate); +} + +#ifdef HAVE_RL_PRE_INPUT_HOOK +static int +on_pre_input_hook(void) +{ + return on_hook(pre_input_hook, pre_input_hook_tstate); +} +#endif + /* C function to call the Python completer. */ static char * @@ -345,7 +443,7 @@ on_completion(char *text, int state) /* Note that readline is called with the interpreter lock released! */ save_tstate = PyThreadState_Swap(NULL); - PyEval_RestoreThread(tstate); + PyEval_RestoreThread(completer_tstate); r = PyObject_CallFunction(completer, "si", text, state); if (r == NULL) goto error; @@ -395,6 +493,11 @@ setup_readline(void) /* Bind both ESC-TAB and ESC-ESC to the completion function */ rl_bind_key_in_map ('\t', rl_complete, emacs_meta_keymap); rl_bind_key_in_map ('\033', rl_complete, emacs_meta_keymap); + /* Set our hook functions */ + rl_startup_hook = (Function *)on_startup_hook; +#ifdef HAVE_RL_PRE_INPUT_HOOK + rl_pre_input_hook = (Function *)on_pre_input_hook; +#endif /* Set our completion function */ rl_attempted_completion_function = (CPPFunction *)flex_complete; /* Set Python word break characters */ |