mirror of
https://github.com/python/cpython.git
synced 2025-12-31 04:23:37 +00:00
Patch #462122: add readline startup and pre_event hooks.
This commit is contained in:
parent
16dc7f44b1
commit
0daad598d0
7 changed files with 211 additions and 35 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
67
configure
vendored
67
configure
vendored
|
|
@ -7027,10 +7027,10 @@ EOF
|
|||
|
||||
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
|
||||
ac_lib_var=`echo readline'_'rl_completion_matches | sed 'y%./+-%__p_%'`
|
||||
# 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
|
||||
|
|
@ -7040,6 +7040,51 @@ 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: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
|
||||
else
|
||||
ac_save_LIBS="$LIBS"
|
||||
LIBS="-lreadline -ltermcap $LIBS"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#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
|
||||
builtin and then its argument prototype would still apply. */
|
||||
char rl_completion_matches();
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -149,6 +149,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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue