diff --git a/NEWS b/NEWS index 7bc53afe7..b46eeb336 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,11 @@ For full details, see the git log at: https://github.com/ksh93/ksh Any uppercase BUG_* names are modernish shell bug IDs. +2021-02-21: + +- Fixed: The way that SIGWINCH was handled (i.e. the signal emitted when the + terminal window size changes) could cause strange emacs/vi editor behaviour. + 2021-02-20: - Fixed a bug introduced on 2021-01-20: if a DEBUG trap action yielded exit diff --git a/src/cmd/ksh93/edit/edit.c b/src/cmd/ksh93/edit/edit.c index f89c6ff7b..3338bd31d 100644 --- a/src/cmd/ksh93/edit/edit.c +++ b/src/cmd/ksh93/edit/edit.c @@ -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); diff --git a/src/cmd/ksh93/edit/emacs.c b/src/cmd/ksh93/edit/emacs.c index aba510468..e52be0fe0 100644 --- a/src/cmd/ksh93/edit/emacs.c +++ b/src/cmd/ksh93/edit/emacs.c @@ -614,10 +614,8 @@ update: } continue; case cntl('L'): - if(!ep->ed->e_nocrnl) - ed_crlf(ep->ed); + ed_crlf(ep->ed); draw(ep,REFRESH); - ep->ed->e_nocrnl = 0; continue; case cntl('[') : vt220_save_repeat = oadjust; @@ -1442,8 +1440,8 @@ static void draw(register Emacs_t *ep,Draw_t option) /*************************************** If in append mode, cursor at end of line, screen up to date, the previous character was a 'normal' character, - and the window has room for another character. - Then output the character and adjust the screen only. + and the window has room for another character, + then output the character and adjust the screen only. *****************************************/ @@ -1555,7 +1553,7 @@ static void draw(register Emacs_t *ep,Draw_t option) } #endif /* SHOPT_MULTIBYTE */ } - if(ep->ed->e_multiline && option == REFRESH && ep->ed->e_nocrnl==0) + if(ep->ed->e_multiline && option == REFRESH) ed_setcursor(ep->ed, ep->screen, ep->cursor-ep->screen, ep->ed->e_peol, -1); @@ -1593,6 +1591,18 @@ static void draw(register Emacs_t *ep,Draw_t option) return; } +/* + * Print the prompt and force a total refresh. + * This is used from edit.c for redrawing the command line upon SIGWINCH. + */ + +void emacs_redraw(void *vp) +{ + Emacs_t *ep = (Emacs_t*)vp; + draw(ep, REFRESH); + ed_flush(ep->ed); +} + /* * put the cursor to the position within screen buffer * if is non-zero then output this character diff --git a/src/cmd/ksh93/edit/vi.c b/src/cmd/ksh93/edit/vi.c index afa1ffb1b..bc0fa0d80 100644 --- a/src/cmd/ksh93/edit/vi.c +++ b/src/cmd/ksh93/edit/vi.c @@ -104,7 +104,6 @@ typedef struct _vi_ char last_find; /* last find command */ char last_cmd; /* last command */ char repeat_set; - char nonewline; int findchar; /* last find char */ genchar *lastline; int first_wind; /* first column of window */ @@ -545,7 +544,7 @@ int ed_viread(void *context, int fd, register char *shbuf, int nchar, int reedit /*** start over since there may be ***/ /*** a control char, or cursor might not ***/ /*** be at left margin (this lets us know ***/ - /*** where we are ***/ + /*** where we are) ***/ cur_phys = 0; window[0] = '\0'; pr_string(vp,Prompt); @@ -819,14 +818,8 @@ static int cntlmode(Vi_t *vp) case cntl('L'): /** Redraw line **/ /*** print the prompt and ***/ /* force a total refresh */ - if(vp->nonewline==0 && !vp->ed->e_nocrnl) - putchar('\n'); - vp->nonewline = 0; - pr_string(vp,Prompt); - window[0] = '\0'; - cur_phys = vp->first_wind; - vp->ofirst_wind = INVALID; - vp->long_line = ' '; + putchar('\n'); + vi_redraw((void*)vp); break; case cntl('V'): @@ -907,8 +900,7 @@ static int cntlmode(Vi_t *vp) vp->ed->hoff--; hupdate: ed_histlist(vp->ed,*vp->ed->hlist!=0); - vp->nonewline++; - ed_ungetchar(vp->ed,cntl('L')); + vi_redraw((void*)vp); continue; } #endif /* SHOPT_EDPREDICT */ @@ -951,9 +943,8 @@ static int cntlmode(Vi_t *vp) ed_histlist(vp->ed,0); if(c=='\n') ed_ungetchar(vp->ed,c); - ed_ungetchar(vp->ed,cntl('L')); - vp->nonewline = 1; cur_virt = 0; + vi_redraw((void*)vp); } #endif /*SHOPT_EDPREDICT */ break; @@ -1873,6 +1864,26 @@ static void putstring(register Vi_t *vp,register int col, register int nchars) return; } +/*{ VI_REDRAW( ) + * + * Print the prompt and force a total refresh. + * + * This is invoked from edit.c for redrawing the command line + * upon SIGWINCH. It is also used by the Ctrl+L routine. + * +}*/ + +void vi_redraw(void *ep) +{ + Vi_t *vp = (Vi_t*)ep; + pr_string(vp,Prompt); + window[0] = '\0'; + cur_phys = vp->first_wind; + vp->ofirst_wind = INVALID; + vp->long_line = ' '; + refresh(vp, *vp->ed->e_vi_insert ? INPUT : CONTROL); +} + /*{ REFRESH( mode ) * * This routine will refresh the crt so the physical image matches @@ -2075,9 +2086,8 @@ static void refresh(register Vi_t* vp, int mode) vp->long_line = vp->long_char; } - if(vp->ed->e_multiline && vp->ofirst_wind==INVALID && !vp->ed->e_nocrnl) + if(vp->ed->e_multiline && vp->ofirst_wind==INVALID) ed_setcursor(vp->ed, physical, last_phys+1, last_phys+1, -1); - vp->ed->e_nocrnl = 0; vp->ocur_phys = ncur_phys; vp->ocur_virt = cur_virt; vp->ofirst_wind = first_w; @@ -2477,8 +2487,7 @@ addin: } else if((c=='=' || (c=='\\'&&virtual[last_virt]=='/')) && !vp->repeat_set) { - vp->nonewline++; - ed_ungetchar(vp->ed,cntl('L')); + vi_redraw((void*)vp); return(GOOD); } else diff --git a/src/cmd/ksh93/include/edit.h b/src/cmd/ksh93/include/edit.h index 4fbb194b5..724ae3f11 100644 --- a/src/cmd/ksh93/include/edit.h +++ b/src/cmd/ksh93/include/edit.h @@ -89,7 +89,6 @@ typedef struct edit int e_lnext; int e_plen; /* length of prompt string */ char e_crlf; /* zero if cannot return to beginning of line */ - char e_nocrnl; /* don't put a new-line with ^L */ char e_keytrap; /* set when in keytrap */ int e_llimit; /* line length limit */ int e_hline; /* current history line number */ @@ -270,4 +269,12 @@ extern int hist_expand(const char *, char **); #endif /* SHOPT_HISTEXPAND */ +#if SHOPT_ESH +extern void emacs_redraw(Void_t*); +#endif /* SHOPT_ESH */ + +#if SHOPT_VSH +extern void vi_redraw(Void_t*); +#endif /* SHOPT_VSH */ + #endif /* !SEARCHSIZE */ diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h index d653eab5a..d848c92c8 100644 --- a/src/cmd/ksh93/include/version.h +++ b/src/cmd/ksh93/include/version.h @@ -20,7 +20,7 @@ #define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */ #define SH_RELEASE_SVER "1.0.0-alpha" /* semantic version number: https://semver.org */ -#define SH_RELEASE_DATE "2021-02-18" /* must be in this format for $((.sh.version)) */ +#define SH_RELEASE_DATE "2021-02-21" /* must be in this format for $((.sh.version)) */ #define SH_RELEASE_CPYR "(c) 2020-2021 Contributors to ksh " SH_RELEASE_FORK /* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */