]> granicus.if.org Git - python/commitdiff
Patch #462122: add readline startup and pre_event hooks.
authorMartin v. Löwis <martin@v.loewis.de>
Sun, 30 Sep 2001 21:09:59 +0000 (21:09 +0000)
committerMartin v. Löwis <martin@v.loewis.de>
Sun, 30 Sep 2001 21:09:59 +0000 (21:09 +0000)
Doc/lib/libreadline.tex
Misc/NEWS
Modules/readline.c
acconfig.h
configure
configure.in
pyconfig.h.in

index a35714449df29bab399bf2c11d12fdfb408904b2..73508453bb15a42418d6d7a1bd0c883748b5d902 100644 (file)
@@ -54,6 +54,22 @@ history file when saving.  Negative values imply unlimited history
 file size.
 \end{funcdesc}
 
+\begin{funcdesc}{set_startup_hook}{\optional{function}}
+Set or remove the startup_hook function.  If \var{function} is specified,
+it will be used as the new startup_hook function; if omitted or
+\code{None}, any hook function already installed is removed.  The
+startup_hook function is called with no arguments just
+before readline prints the first prompt.
+\end{funcdesc}
+
+\begin{funcdesc}{set_pre_input_hook}{\optional{function}}
+Set or remove the pre_input_hook function.  If \var{function} is specified,
+it will be used as the new pre_input_hook function; if omitted or
+\code{None}, any hook function already installed is removed.  The
+pre_input_hook function is called with no arguments after the first prompt
+has been printed and just before readline starts reading input characters.
+\end{funcdesc}
+
 \begin{funcdesc}{set_completer}{\optional{function}}
 Set or remove the completer function.  If \var{function} is specified,
 it will be used as the new completer function; if omitted or
index 4b6ae5b7f6d47ba8b74941e110734f5a6c39b644..b7ccc862ca2b37550f11e3f7758ba3ccf766ffa0 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -8,6 +8,8 @@ Core
 
 - binascii has now two quopri support functions, a2b_qp and b2a_qp.
 
+- readline now supports setting the startup_hook and the pre_event_hook.
+
 Library
 
 - quopri's encode and decode methods take an optional header parameter,
index 6469d27ec610f2e29d775dc7d5c554d65280f17b..49839c4c2b2716efc654ac9c1a7602e7cc11a27d 100644 (file)
@@ -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 */
index ded68bbb9f63b0c14b9bae8810b8f68a260135dc..9e30ab5e3b76b7f28518b6304de5dba8255e89ec 100644 (file)
@@ -87,6 +87,9 @@
 /* Define if you have GNU PTH threads */
 #undef HAVE_PTH
 
+/* Define if you have readline 4.0 */
+#undef HAVE_RL_PRE_INPUT_HOOK
+
 /* Define if you have readline 4.2 */
 #undef HAVE_RL_COMPLETION_MATCHES
 
index ca245d3bce854e09f3db762bd8cf93ca5d58e4d1..d4af9b2b6c50cf71566d276bb8736572ba51de0d 100755 (executable)
--- a/configure
+++ b/configure
@@ -7027,9 +7027,54 @@ EOF
 
 fi
 
+# check for readline 4.0
+echo $ac_n "checking for rl_pre_input_hook in -lreadline""... $ac_c" 1>&6
+echo "configure:7033: checking for rl_pre_input_hook in -lreadline" >&5
+ac_lib_var=`echo readline'_'rl_pre_input_hook | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lreadline -ltermcap $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 7041 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char rl_pre_input_hook();
+
+int main() {
+rl_pre_input_hook()
+; return 0; }
+EOF
+if { (eval echo configure:7052: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_RL_PRE_INPUT_HOOK 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
 # check for readline 4.2
 echo $ac_n "checking for rl_completion_matches in -lreadline""... $ac_c" 1>&6
-echo "configure:7033: checking for rl_completion_matches in -lreadline" >&5
+echo "configure:7078: checking for rl_completion_matches in -lreadline" >&5
 ac_lib_var=`echo readline'_'rl_completion_matches | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -7037,7 +7082,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lreadline -ltermcap $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 7041 "configure"
+#line 7086 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -7048,7 +7093,7 @@ int main() {
 rl_completion_matches()
 ; return 0; }
 EOF
-if { (eval echo configure:7052: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:7097: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -7073,7 +7118,7 @@ fi
 
 
 echo $ac_n "checking for broken nice()""... $ac_c" 1>&6
-echo "configure:7077: checking for broken nice()" >&5
+echo "configure:7122: checking for broken nice()" >&5
 if eval "test \"`echo '$''{'ac_cv_broken_nice'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -7082,7 +7127,7 @@ if test "$cross_compiling" = yes; then
   ac_cv_broken_nice=no
 else
   cat > conftest.$ac_ext <<EOF
-#line 7086 "configure"
+#line 7131 "configure"
 #include "confdefs.h"
 
 int main()
@@ -7094,7 +7139,7 @@ int main()
 }
 
 EOF
-if { (eval echo configure:7098: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:7143: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_broken_nice=yes
 else
@@ -7125,12 +7170,12 @@ cat >> confdefs.h <<\EOF
 #endif
 EOF
 echo $ac_n "checking for socklen_t""... $ac_c" 1>&6
-echo "configure:7129: checking for socklen_t" >&5
+echo "configure:7174: checking for socklen_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_socklen_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 7134 "configure"
+#line 7179 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -7179,7 +7224,7 @@ done
 
 SRCDIRS="Parser Grammar Objects Python Modules"
 echo $ac_n "checking for build directories""... $ac_c" 1>&6
-echo "configure:7183: checking for build directories" >&5
+echo "configure:7228: checking for build directories" >&5
 for dir in $SRCDIRS; do
     if test ! -d $dir; then
         mkdir $dir
index 31412a19dee57f424e20143dc81a9a05b31576a0..d8fffc0a553864effc9cf104737ff57e8af1a758 100644 (file)
@@ -1832,6 +1832,10 @@ then
   AC_DEFINE(HAVE_GETC_UNLOCKED)
 fi
 
+# check for readline 4.0
+AC_CHECK_LIB(readline, rl_pre_input_hook,
+       AC_DEFINE(HAVE_RL_PRE_INPUT_HOOK), , -ltermcap)
+
 # check for readline 4.2
 AC_CHECK_LIB(readline, rl_completion_matches,
        AC_DEFINE(HAVE_RL_COMPLETION_MATCHES), , -ltermcap)
index 9250e668caa859c57343eeea2fa9163535b6c0c1..00dea7503dfad44d8ad773ac5214db521ffd13f3 100644 (file)
 /* Define if you have GNU PTH threads */
 #undef HAVE_PTH
 
+/* Define if you have readline 4.0 */
+#undef HAVE_RL_PRE_INPUT_HOOK
+
 /* Define if you have readline 4.2 */
 #undef HAVE_RL_COMPLETION_MATCHES