[Python-checkins] CVS: python/dist/src/Modules readline.c,2.37,2.38

Martin v. L?wis loewis@users.sourceforge.net
Sun, 30 Sep 2001 14:10:01 -0700


Update of /cvsroot/python/python/dist/src/Modules
In directory usw-pr-cvs1:/tmp/cvs-serv18073/Modules

Modified Files:
	readline.c 
Log Message:
Patch #462122: add readline startup and pre_event hooks.


Index: readline.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/readline.c,v
retrieving revision 2.37
retrieving revision 2.38
diff -C2 -d -r2.37 -r2.38
*** readline.c	2001/08/01 21:44:14	2.37
--- readline.c	2001/09/30 21:09:59	2.38
***************
*** 159,168 ****
  }
  
  
  
  /* Exported function to specify a word completer in Python */
  
  static PyObject *completer = NULL;
! static PyThreadState *tstate = NULL;
  
  static PyObject *begidx = NULL;
--- 159,236 ----
  }
  
+ /* 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 *completer_tstate = NULL;
  
  static PyObject *begidx = NULL;
***************
*** 239,264 ****
  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;
  }
  
--- 307,311 ----
  set_completer(PyObject *self, PyObject *args)
  {
! 	return set_hook("completer", &completer, &completer_tstate, args);
  }
  
***************
*** 331,337 ****
--- 378,435 ----
  	{"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. */
  
***************
*** 346,350 ****
  		   lock released! */
  		save_tstate = PyThreadState_Swap(NULL);
! 		PyEval_RestoreThread(tstate);
  		r = PyObject_CallFunction(completer, "si", text, state);
  		if (r == NULL)
--- 444,448 ----
  		   lock released! */
  		save_tstate = PyThreadState_Swap(NULL);
! 		PyEval_RestoreThread(completer_tstate);
  		r = PyObject_CallFunction(completer, "si", text, state);
  		if (r == NULL)
***************
*** 396,399 ****
--- 494,502 ----
  	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;