@@ -158,12 +158,80 @@ get_history_length(PyObject *self, PyObject *args)
158158 return Py_BuildValue ("i" , history_length );
159159}
160160
161+ /* Generic hook function setter */
161162
163+ static PyObject *
164+ set_hook (const char * funcname , PyObject * * hook_var , PyThreadState * * tstate , PyObject * args )
165+ {
166+ PyObject * function = Py_None ;
167+ char buf [80 ];
168+ sprintf (buf , "|O:set_%s" , funcname );
169+ if (!PyArg_ParseTuple (args , buf , & function ))
170+ return NULL ;
171+ if (function == Py_None ) {
172+ Py_XDECREF (* hook_var );
173+ * hook_var = NULL ;
174+ * tstate = NULL ;
175+ }
176+ else if (PyCallable_Check (function )) {
177+ PyObject * tmp = * hook_var ;
178+ Py_INCREF (function );
179+ * hook_var = function ;
180+ Py_XDECREF (tmp );
181+ * tstate = PyThreadState_Get ();
182+ }
183+ else {
184+ sprintf (buf , "set_%s(func): argument not callable" , funcname );
185+ PyErr_SetString (PyExc_TypeError , buf );
186+ return NULL ;
187+ }
188+ Py_INCREF (Py_None );
189+ return Py_None ;
190+ }
191+
192+ /* Exported functions to specify hook functions in Python */
193+
194+ static PyObject * startup_hook = NULL ;
195+ static PyThreadState * startup_hook_tstate = NULL ;
196+
197+ #ifdef HAVE_RL_PRE_INPUT_HOOK
198+ static PyObject * pre_input_hook = NULL ;
199+ static PyThreadState * pre_input_hook_tstate = NULL ;
200+ #endif
201+
202+ static PyObject *
203+ set_startup_hook (PyObject * self , PyObject * args )
204+ {
205+ return set_hook ("startup_hook" , & startup_hook , & startup_hook_tstate , args );
206+ }
207+
208+ static char doc_set_startup_hook [] = "\
209+ set_startup_hook([function]) -> None\n\
210+ Set or remove the startup_hook function.\n\
211+ The function is called with no arguments just\n\
212+ before readline prints the first prompt.\n\
213+ " ;
214+
215+ #ifdef HAVE_RL_PRE_INPUT_HOOK
216+ static PyObject *
217+ set_pre_input_hook (PyObject * self , PyObject * args )
218+ {
219+ return set_hook ("pre_input_hook" , & pre_input_hook , & pre_input_hook_tstate , args );
220+ }
221+
222+ static char doc_set_pre_input_hook [] = "\
223+ set_pre_input_hook([function]) -> None\n\
224+ Set or remove the pre_input_hook function.\n\
225+ The function is called with no arguments after the first prompt\n\
226+ has been printed and just before readline starts reading input\n\
227+ characters.\n\
228+ " ;
229+ #endif
162230
163231/* Exported function to specify a word completer in Python */
164232
165233static PyObject * completer = NULL ;
166- static PyThreadState * tstate = NULL ;
234+ static PyThreadState * completer_tstate = NULL ;
167235
168236static PyObject * begidx = NULL ;
169237static PyObject * endidx = NULL ;
@@ -238,28 +306,7 @@ get the readline word delimiters for tab-completion";
238306static PyObject *
239307set_completer (PyObject * self , PyObject * args )
240308{
241- PyObject * function = Py_None ;
242- if (!PyArg_ParseTuple (args , "|O:set_completer" , & function ))
243- return NULL ;
244- if (function == Py_None ) {
245- Py_XDECREF (completer );
246- completer = NULL ;
247- tstate = NULL ;
248- }
249- else if (PyCallable_Check (function )) {
250- PyObject * tmp = completer ;
251- Py_INCREF (function );
252- completer = function ;
253- Py_XDECREF (tmp );
254- tstate = PyThreadState_Get ();
255- }
256- else {
257- PyErr_SetString (PyExc_TypeError ,
258- "set_completer(func): argument not callable" );
259- return NULL ;
260- }
261- Py_INCREF (Py_None );
262- return Py_None ;
309+ return set_hook ("completer" , & completer , & completer_tstate , args );
263310}
264311
265312static char doc_set_completer [] = "\
@@ -330,9 +377,60 @@ static struct PyMethodDef readline_methods[] =
330377 METH_VARARGS , doc_set_completer_delims },
331378 {"get_completer_delims" , get_completer_delims ,
332379 METH_OLDARGS , doc_get_completer_delims },
380+
381+ {"set_startup_hook" , set_startup_hook , METH_VARARGS , doc_set_startup_hook },
382+ #ifdef HAVE_RL_PRE_INPUT_HOOK
383+ {"set_pre_input_hook" , set_pre_input_hook , METH_VARARGS , doc_set_pre_input_hook },
384+ #endif
333385 {0 , 0 }
334386};
335387
388+ /* C function to call the Python hooks. */
389+
390+ static int
391+ on_hook (PyObject * func , PyThreadState * tstate )
392+ {
393+ int result = 0 ;
394+ if (func != NULL ) {
395+ PyObject * r ;
396+ PyThreadState * save_tstate ;
397+ /* Note that readline is called with the interpreter
398+ lock released! */
399+ save_tstate = PyThreadState_Swap (NULL );
400+ PyEval_RestoreThread (tstate );
401+ r = PyObject_CallFunction (func , NULL );
402+ if (r == NULL )
403+ goto error ;
404+ if (r == Py_None )
405+ result = 0 ;
406+ else
407+ result = PyInt_AsLong (r );
408+ Py_DECREF (r );
409+ goto done ;
410+ error :
411+ PyErr_Clear ();
412+ Py_XDECREF (r );
413+ done :
414+ PyEval_SaveThread ();
415+ PyThreadState_Swap (save_tstate );
416+ }
417+ return result ;
418+ }
419+
420+ static int
421+ on_startup_hook (void )
422+ {
423+ return on_hook (startup_hook , startup_hook_tstate );
424+ }
425+
426+ #ifdef HAVE_RL_PRE_INPUT_HOOK
427+ static int
428+ on_pre_input_hook (void )
429+ {
430+ return on_hook (pre_input_hook , pre_input_hook_tstate );
431+ }
432+ #endif
433+
336434/* C function to call the Python completer. */
337435
338436static char *
@@ -345,7 +443,7 @@ on_completion(char *text, int state)
345443 /* Note that readline is called with the interpreter
346444 lock released! */
347445 save_tstate = PyThreadState_Swap (NULL );
348- PyEval_RestoreThread (tstate );
446+ PyEval_RestoreThread (completer_tstate );
349447 r = PyObject_CallFunction (completer , "si" , text , state );
350448 if (r == NULL )
351449 goto error ;
@@ -395,6 +493,11 @@ setup_readline(void)
395493 /* Bind both ESC-TAB and ESC-ESC to the completion function */
396494 rl_bind_key_in_map ('\t' , rl_complete , emacs_meta_keymap );
397495 rl_bind_key_in_map ('\033' , rl_complete , emacs_meta_keymap );
496+ /* Set our hook functions */
497+ rl_startup_hook = (Function * )on_startup_hook ;
498+ #ifdef HAVE_RL_PRE_INPUT_HOOK
499+ rl_pre_input_hook = (Function * )on_pre_input_hook ;
500+ #endif
398501 /* Set our completion function */
399502 rl_attempted_completion_function = (CPPFunction * )flex_complete ;
400503 /* Set Python word break characters */
0 commit comments