mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
editors: fix broken SIGWINCH handling
In the emacs editor: 1. press ESC 2. change the size of your terminal window and your screen is mysteriously cleared. (Until recent fixes, the shell probably also crashed somewhere in the job control code.) The cause is the way SIGWINCH is handled by ed_read() in edit.c. For the emacs editor, it sends a Ctrl+L character to the input buffer. The Ctrl+L command refreshes the command line. And it so happens that ESC plus Ctrl+L is a command to clear the screen in the emacs editor. With the exeption of vi insert/command mode for which it uses a shared flag, edit.c does not know the state of the editor, because their data are internal to emacs.c and vi.c. So it doesn't know whether you're in some mode that treats keyboard input specially. Which means this way of dealing with SIGWINCH is fundamentally misdesigned and is not worth fixing. It gets sillier: in addition to sending keyboard commands, edit.c was also communicating directly with emacs.c and vi.c via a flag, e_nocrnl, which means 'please don't make Ctrl+L emit a linefeed' (it normally refreshes on a new line but that is undesirable for SIGWINCH). So there is already a hack that breaks the barrier between edit.c and emacs.c/vi.c. Let's do that properly instead. As of this commit, ed_read() does not send any fake keystrokes. Instead, two extern functions, emacs_redraw() and vi_redraw(), are defined for redrawing the command line. These are put in emacs.c and vi.c so they have access to relevant static data and functions. Then, instead of sending keyboard commands to the editor and returning, ed_read() simply calls the redraw function for the active editor, then continues and waits for input. Much cleaner. src/cmd/ksh93/include/edit.h: - Remove e_nocrnl flag from Edit_t struct. - Define externs emacs_redraw() and vi_redraw(). Since Emacs_t and Vi_t types are not known here, we have to declare void* pointers and the functions will have to use typecasts. src/cmd/ksh93/edit/edit.c: - ed_read(): Call emacs_redraw() or vi_redraw() as per above. - ed_getchar(): Remove comment about a nonexistent while loop. src/cmd/ksh93/edit/emacs.c: - Updates corresponding to removal of e_nocrnl flag. - Add emacs_redraw(). This one is pretty simple. Refresh the command line, then ed_flush() to update the cursor display. src/cmd/ksh93/edit/vi.c: - Updates corresponding to removal of e_nocrnl flag. Also remove a similar internal 'nonewline' flag which is now equally redundant. - Move the Ctrl+L handling code (minus writing the newline) into the vi_redraw() function. - Change two cases where vi set nonewline and sent Ctrl+L to itself into simple vi_redraw() calls. - Add vi_redraw(). This is more complicated as it incorporates the previous Ctrl+L code. It needs an added refresh() call with a check whether we're currently in command or insert mode, as those use different refresh methods. Luckily edit.c already maintains an *e_vi_insert flag in ed_getchar() that we can use. Since vi's refresh() already calls ed_flush(), we don't need to add that.
This commit is contained in:
parent
18529b88c6
commit
83630f9d1c
6 changed files with 76 additions and 45 deletions
|
@ -829,11 +829,14 @@ static void ed_nputchar(register Edit_t *ep, int n, int c)
|
|||
/*
|
||||
* Do read, restart on interrupt unless SH_SIGSET or SH_SIGTRAP is set
|
||||
* Use sfpkrd() to poll() or select() to wait for input if possible
|
||||
*
|
||||
* The return value is the number of bytes read, or < 0 for EOF.
|
||||
*
|
||||
* Unfortunately, systems that get interrupted from slow reads update
|
||||
* this access time for the terminal (in violation of POSIX).
|
||||
* The fixtime() macro, resets the time to the time at entry in
|
||||
* The fixtime() macro resets the time to the time at entry in
|
||||
* this case. This is not necessary for systems that can handle
|
||||
* sfpkrd() correctly (i,e., those that support poll() or select()
|
||||
* sfpkrd() correctly (i.e., those that support poll() or select()).
|
||||
*/
|
||||
int ed_read(void *context, int fd, char *buff, int size, int reedit)
|
||||
{
|
||||
|
@ -858,11 +861,11 @@ int ed_read(void *context, int fd, char *buff, int size, int reedit)
|
|||
if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
|
||||
goto done;
|
||||
#if SHOPT_ESH && SHOPT_VSH
|
||||
if(ep->sh->winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_VI) || sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS)))
|
||||
if(shp->winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_VI) || sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS)))
|
||||
#elif SHOPT_ESH
|
||||
if(ep->sh->winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS)))
|
||||
if(shp->winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS)))
|
||||
#elif SHOPT_VSH
|
||||
if(ep->sh->winch && sh_isstate(SH_INTERACTIVE) && sh_isoption(SH_VI))
|
||||
if(shp->winch && sh_isstate(SH_INTERACTIVE) && sh_isoption(SH_VI))
|
||||
#else
|
||||
if(0)
|
||||
#endif
|
||||
|
@ -889,7 +892,6 @@ int ed_read(void *context, int fd, char *buff, int size, int reedit)
|
|||
while(n--)
|
||||
ed_putstring(ep,CURSOR_UP);
|
||||
}
|
||||
ep->sh->winch = 0;
|
||||
ed_flush(ep);
|
||||
sh_delay(.05,0);
|
||||
astwinsize(2,&rows,&newsize);
|
||||
|
@ -898,19 +900,18 @@ int ed_read(void *context, int fd, char *buff, int size, int reedit)
|
|||
ep->e_winsz = MINWINDOW;
|
||||
if(!ep->e_multiline && ep->e_wsize < MAXLINE)
|
||||
ep->e_wsize = ep->e_winsz-2;
|
||||
ep->e_nocrnl=1;
|
||||
if(*ep->e_vi_insert)
|
||||
{
|
||||
buff[0] = ESC;
|
||||
buff[1] = cntl('L');
|
||||
buff[2] = 'a';
|
||||
return(3);
|
||||
}
|
||||
buff[0] = cntl('L');
|
||||
return(1);
|
||||
#if SHOPT_ESH && SHOPT_VSH
|
||||
if(sh_isoption(SH_VI))
|
||||
vi_redraw(ep->e_vi);
|
||||
else
|
||||
emacs_redraw(ep->e_emacs);
|
||||
#elif SHOPT_VSH
|
||||
vi_redraw(ep->e_vi);
|
||||
#elif SHOPT_ESH
|
||||
emacs_redraw(ep->e_emacs);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
ep->sh->winch = 0;
|
||||
shp->winch = 0;
|
||||
/* an interrupt that should be ignored */
|
||||
errno = 0;
|
||||
if(!waitevent || (rv=(*waitevent)(fd,-1L,0))>=0)
|
||||
|
@ -1072,7 +1073,6 @@ int ed_getchar(register Edit_t *ep,int mode)
|
|||
{
|
||||
ed_flush(ep);
|
||||
ep->e_inmacro = 0;
|
||||
/* The while is necessary for reads of partial multibyte chars */
|
||||
*ep->e_vi_insert = (mode==-2);
|
||||
if((n=ed_read(ep,ep->e_fd,readin,-LOOKAHEAD,0)) > 0)
|
||||
n = putstack(ep,readin,n,1);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue