diff --git a/Misc/ACKS b/Misc/ACKS index 52eae6944d4..20e76f56aee 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1160,6 +1160,7 @@ Florian Preinstorfer Amrit Prem Paul Prescod Donovan Preston +Eric Price Paul Price Iuliia Proskurnia Dorian Pula diff --git a/Misc/NEWS b/Misc/NEWS index f66014a7dc9..8cd2339f953 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -237,6 +237,9 @@ Core and Builtins Library ------- +- Issue #23735: Handle terminal resizing with Readline 6.3+ by installing our + own SIGWINCH handler. Patch by Eric Price. + - Issue #25951: Change SSLSocket.sendall() to return None, as explicitly documented for plain socket objects. Patch by Aviv Palivoda. diff --git a/Modules/readline.c b/Modules/readline.c index cd93b629652..9770f52c75f 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -926,6 +926,26 @@ on_completion_display_matches_hook(char **matches, #endif +#ifdef HAVE_RL_RESIZE_TERMINAL +static volatile sig_atomic_t sigwinch_received; +static sighandler_t sigwinch_ohandler; + +static void +readline_sigwinch_handler(int signum) +{ + sigwinch_received = 1; + if (sigwinch_ohandler && + sigwinch_ohandler != SIG_IGN && sigwinch_ohandler != SIG_DFL) + sigwinch_ohandler(signum); + +#ifndef HAVE_SIGACTION + /* If the handler was installed with signal() rather than sigaction(), + we need to reinstall it. */ + PyOS_setsig(SIGWINCH, readline_sigwinch_handler); +#endif +} +#endif + /* C function to call the Python completer. */ static char * @@ -1031,6 +1051,10 @@ setup_readline(readlinestate *mod_state) /* 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); +#ifdef HAVE_RL_RESIZE_TERMINAL + /* Set up signal handler for window resize */ + sigwinch_ohandler = PyOS_setsig(SIGWINCH, readline_sigwinch_handler); +#endif /* Set our hook functions */ rl_startup_hook = on_startup_hook; #ifdef HAVE_RL_PRE_INPUT_HOOK @@ -1116,6 +1140,13 @@ readline_until_enter_or_signal(const char *prompt, int *signal) struct timeval *timeoutp = NULL; if (PyOS_InputHook) timeoutp = &timeout; +#ifdef HAVE_RL_RESIZE_TERMINAL + /* Update readline's view of the window size after SIGWINCH */ + if (sigwinch_received) { + sigwinch_received = 0; + rl_resize_terminal(); + } +#endif FD_SET(fileno(rl_instream), &selectset); /* select resets selectset if no input was available */ has_input = select(fileno(rl_instream) + 1, &selectset, diff --git a/configure b/configure index 7bef2d3c0af..5f456a20287 100755 --- a/configure +++ b/configure @@ -14929,6 +14929,50 @@ $as_echo "#define HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK 1" >>confdefs.h fi +# also in 4.0, but not in editline +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_resize_terminal in -lreadline" >&5 +$as_echo_n "checking for rl_resize_terminal in -lreadline... " >&6; } +if ${ac_cv_lib_readline_rl_resize_terminal+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lreadline $READLINE_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char rl_resize_terminal (); +int +main () +{ +return rl_resize_terminal (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_readline_rl_resize_terminal=yes +else + ac_cv_lib_readline_rl_resize_terminal=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_resize_terminal" >&5 +$as_echo "$ac_cv_lib_readline_rl_resize_terminal" >&6; } +if test "x$ac_cv_lib_readline_rl_resize_terminal" = xyes; then : + +$as_echo "#define HAVE_RL_RESIZE_TERMINAL 1" >>confdefs.h + +fi + + # check for readline 4.2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_completion_matches in -lreadline" >&5 $as_echo_n "checking for rl_completion_matches in -lreadline... " >&6; } diff --git a/configure.ac b/configure.ac index 98e9703e6f8..1aea63ce470 100644 --- a/configure.ac +++ b/configure.ac @@ -4527,6 +4527,11 @@ AC_CHECK_LIB(readline, rl_completion_display_matches_hook, AC_DEFINE(HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK, 1, [Define if you have readline 4.0]), ,$READLINE_LIBS) +# also in 4.0, but not in editline +AC_CHECK_LIB(readline, rl_resize_terminal, + AC_DEFINE(HAVE_RL_RESIZE_TERMINAL, 1, + [Define if you have readline 4.0]), ,$READLINE_LIBS) + # check for readline 4.2 AC_CHECK_LIB(readline, rl_completion_matches, AC_DEFINE(HAVE_RL_COMPLETION_MATCHES, 1, diff --git a/pyconfig.h.in b/pyconfig.h.in index e017d4ea316..d432a821a57 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -735,6 +735,9 @@ /* Define if you have readline 4.0 */ #undef HAVE_RL_PRE_INPUT_HOOK +/* Define if you have readline 4.0 */ +#undef HAVE_RL_RESIZE_TERMINAL + /* Define to 1 if you have the `round' function. */ #undef HAVE_ROUND