From 72c797015c3a470a59106cd86bc18e63a7b2fd4e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 13 Dec 2014 07:41:59 +0000 Subject: [PATCH] nvi forgets to switch tty from ex mode on q when there are other screens nvi forgets to switch tty mode if, in ex mode, you give it 'q' with more than one screen present. The minimal reproducer is :ViQq After that you are back in vi mode, but tty is still set up for ex - input is echoed and line-buffered. In that state Qvi recovers the normal state; :vi does not. Bug goes _way_ back - at the very least to 1.79, and I wouldn't be surprised if it was as old as the introduction of multi-screen support. The same fix applies to older versions. ex mode interpreter treats SC_EXIT flag set by ex_quit() as "find the next screen, leave it for caller to handle after we return, kill the current one and return to caller". Then the caller (editor()) proceeds to call either vi() or ex() it, depending on SC_EX flag for the new screen. Both call ->scr_screen(), passing it the desired mode. Unfortunately, cl_screen() (normal ->scr_screen() callback) checks the current tty mode (SC_SCR_{EX,VI}) in flags, and if the desired mode matches what we (think we) have it does nothing. In this case we end up with tty mode matching the SC_SCR_... flags for *old* screen. The one we switch to has SC_SCR_VI and SC_VI, so we proceed to call vi(), which calls cl_screen(new_screen, SC_VI). Which decides that there's nothing for it to do. As the result we are left in vi mode with buggered tty settings. Entering Qvi recovers things since handling 'Q' sets SC_EX and leaves vi(), with ex() getting called on the same screen. That calls cl_screen(screen, SC_EX), which does (needless) switch of tty setting for ex mode and sets SC_SCR_EX. Handling of "vi" sets SC_VI and leaves ex(). Now we call vi() again, but this time around we do have SC_SCR_EX, so cl_screen() called by vi() *does* switch tty mode properly. Fix is obvious - transfer SC_SCR_... flags from old screen to new one, when ex() sees SC_EXIT/SC_EXIT_FORCE. Signed-off-by: Al Viro Signed-off-by: Sven Verdoolaege --- ex/ex.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ex/ex.c b/ex/ex.c index dae0cc86..3dba5bfc 100644 --- a/ex/ex.c +++ b/ex/ex.c @@ -162,6 +162,10 @@ ex(SCR **spp) if (file_end(sp, NULL, F_ISSET(sp, SC_EXIT_FORCE))) return (1); *spp = screen_next(sp); + if (*spp) { + F_CLR(*spp, SC_SCR_VI); + F_SET(*spp, SC_SCR_EX); + } return (screen_end(sp)); } } -- 2.11.4.GIT