diff --git a/ChangeLog b/ChangeLog index d4d213167..b90f8cef6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2002-07-01 Peter Stephenson + + * 17384: Src/Zle/zle_main.c, Src/Zle/iwidgets.list, + Doc/Zsh/zle.yo: new `recursive-edit' widget allows a user-defined + widget to pass control back to zle as a subcommand. + 2002-07-01 Sven Wischnowsky * 17387: Completion/Zsh/Context/.distfiles, diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index f7210e7a6..0cc1b52df 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -1620,6 +1620,48 @@ At a secondary (tt(PS2)) prompt, move the entire current multiline construct into the editor buffer. The latter is equivalent to tt(push-input) followed by tt(get-line). ) +tindex(recursive-edit) +item(tt(recursive-edit))( +Only useful from a user-defined widget. At this point in the function, +the editor regains control until one of the standard widgets which would +normally cause zle to exit (typically an tt(accept-line) caused by +hitting the return key) is executed. Instead, control returns to the +user-defined widget. The status returned is non-zero if the return was +caused by an error, but the function still continues executing and hence +may tidy up. This makes it safe for the user-defined widget to alter +the command line or key bindings temporarily. + + +The following widget, tt(caps-lock), serves as an example. +example(self-insert-ucase() { + LBUFFER+=${(U)KEYS[-1]} +} + +integer stat + +zle -N self-insert self-insert-ucase +zle -A caps-lock save-caps-lock +zle -A accept-line caps-lock + +zle recursive-edit +stat=$? + +zle -A .self-insert self-insert +zle -A save-caps-lock caps-lock +zle -D save-caps-lock + +(( stat )) && zle send-break + +return $stat +) +This causes typed letters to be inserted capitalised until either +tt(accept-line) (i.e. typically the return key) is typed or the +tt(caps-lock) widget is invoked again; the later is handled by saving +the old definition of tt(caps-lock) as tt(save-caps-lock) and then +rebinding it to invoke tt(accept-line). Note that an error from the +recursive edit is detected as a non-zero return status and propagated by +using the tt(send-break) widget. +) tindex(redisplay) item(tt(redisplay) (unbound) (^R) (^R))( Redisplays the edit buffer. diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list index da5bcc531..fbd45dacc 100644 --- a/Src/Zle/iwidgets.list +++ b/Src/Zle/iwidgets.list @@ -85,6 +85,7 @@ "quoted-insert", quotedinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX "quote-line", quoteline, 0 "quote-region", quoteregion, 0 +"recursive-edit", recursiveedit, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "redisplay", redisplay, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "redo", redo, ZLE_KEEPSUFFIX "reverse-menu-complete", reversemenucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 782bd472c..9332b509d 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -89,10 +89,11 @@ mod_export int eofchar; static int eofsent; static long keytimeout; -#ifdef HAVE_SELECT +#if defined(HAVE_SELECT) || defined(HAVE_POLL) /* Terminal baud rate */ static int baud; +static long costmult; #endif /* flags associated with last command */ @@ -631,108 +632,19 @@ getkey(int keytmout) return ret; } -/* Read a line. It is returned metafied. */ - /**/ -unsigned char * -zleread(char *lp, char *rp, int flags) +void +zlecore(void) { - unsigned char *s; - int old_errno = errno; - int tmout = getiparam("TMOUT"); - -#if defined(HAVE_SELECT) || defined(HAVE_POLL) - long costmult; -# ifdef HAVE_POLL -# else +#if !defined(HAVE_POLL) && defined(HAVE_SELECT) struct timeval tv; fd_set foofd; -# endif - baud = getiparam("BAUD"); - costmult = (baud) ? 3840000L / baud : 0; -#endif - - /* ZLE doesn't currently work recursively. This is needed in case a * - * select loop is used in a function called from ZLE. vared handles * - * this differently itself. */ - if(zleactive) { - char *pptbuf; - int pptlen; - - pptbuf = unmetafy(promptexpand(lp, 0, NULL, NULL), &pptlen); - write(2, (WRITE_ARG_2_T)pptbuf, pptlen); - free(pptbuf); - return (unsigned char *)shingetline(); - } - - keytimeout = getiparam("KEYTIMEOUT"); - if (!shout) { - if (SHTTY != -1) - init_shout(); - - if (!shout) - return NULL; - /* We could be smarter and default to a system read. */ - - /* If we just got a new shout, make sure the terminal is set up. */ - if (termflags & TERM_UNKNOWN) - init_term(); - } - - fflush(shout); - fflush(stderr); - intr(); - insmode = unset(OVERSTRIKE); - eofsent = 0; - resetneeded = 0; - lpromptbuf = promptexpand(lp, 1, NULL, NULL); - pmpt_attr = txtchange; - rpromptbuf = promptexpand(rp, 1, NULL, NULL); - rpmpt_attr = txtchange; - - zlereadflags = flags; - histline = curhist; -#ifndef HAVE_POLL -# ifdef HAVE_SELECT FD_ZERO(&foofd); -# endif #endif - undoing = 1; - line = (unsigned char *)zalloc((linesz = 256) + 2); - virangeflag = lastcmd = done = cs = ll = mark = 0; - vichgflag = 0; - viinsbegin = 0; - statusline = NULL; - selectkeymap("main", 1); - selectlocalmap(NULL); - fixsuffix(); - if ((s = (unsigned char *)getlinknode(bufstack))) { - setline((char *)s); - zsfree((char *)s); - if (stackcs != -1) { - cs = stackcs; - stackcs = -1; - if (cs > ll) - cs = ll; - } - if (stackhist != -1) { - histline = stackhist; - stackhist = -1; - } - } - initundo(); - if (isset(PROMPTCR)) - putc('\r', shout); - if (tmout) - alarm(tmout); - zleactive = 1; - resetneeded = 1; - errflag = retflag = 0; - lastcol = -1; - initmodifier(&zmod); - prefixflag = 0; + zrefresh(); + while (!done && !errflag) { statusline = NULL; @@ -786,6 +698,100 @@ zleread(char *lp, char *rp, int flags) if (!kungetct) zrefresh(); } +} + +/* Read a line. It is returned metafied. */ + +/**/ +unsigned char * +zleread(char *lp, char *rp, int flags) +{ + unsigned char *s; + int old_errno = errno; + int tmout = getiparam("TMOUT"); + +#if defined(HAVE_POLL) || defined(HAVE_SELECT) + baud = getiparam("BAUD"); + costmult = (baud) ? 3840000L / baud : 0; +#endif + + /* ZLE doesn't currently work recursively. This is needed in case a * + * select loop is used in a function called from ZLE. vared handles * + * this differently itself. */ + if(zleactive) { + char *pptbuf; + int pptlen; + + pptbuf = unmetafy(promptexpand(lp, 0, NULL, NULL), &pptlen); + write(2, (WRITE_ARG_2_T)pptbuf, pptlen); + free(pptbuf); + return (unsigned char *)shingetline(); + } + + keytimeout = getiparam("KEYTIMEOUT"); + if (!shout) { + if (SHTTY != -1) + init_shout(); + + if (!shout) + return NULL; + /* We could be smarter and default to a system read. */ + + /* If we just got a new shout, make sure the terminal is set up. */ + if (termflags & TERM_UNKNOWN) + init_term(); + } + + fflush(shout); + fflush(stderr); + intr(); + insmode = unset(OVERSTRIKE); + eofsent = 0; + resetneeded = 0; + lpromptbuf = promptexpand(lp, 1, NULL, NULL); + pmpt_attr = txtchange; + rpromptbuf = promptexpand(rp, 1, NULL, NULL); + rpmpt_attr = txtchange; + + zlereadflags = flags; + histline = curhist; + undoing = 1; + line = (unsigned char *)zalloc((linesz = 256) + 2); + virangeflag = lastcmd = done = cs = ll = mark = 0; + vichgflag = 0; + viinsbegin = 0; + statusline = NULL; + selectkeymap("main", 1); + selectlocalmap(NULL); + fixsuffix(); + if ((s = (unsigned char *)getlinknode(bufstack))) { + setline((char *)s); + zsfree((char *)s); + if (stackcs != -1) { + cs = stackcs; + stackcs = -1; + if (cs > ll) + cs = ll; + } + if (stackhist != -1) { + histline = stackhist; + stackhist = -1; + } + } + initundo(); + if (isset(PROMPTCR)) + putc('\r', shout); + if (tmout) + alarm(tmout); + zleactive = 1; + resetneeded = 1; + errflag = retflag = 0; + lastcol = -1; + initmodifier(&zmod); + prefixflag = 0; + + zlecore(); + statusline = NULL; invalidatelist(); trashzle(); @@ -1233,6 +1239,20 @@ whereis(char **args) return 0; } +/**/ +int +recursiveedit(char **args) +{ + int locerror; + + zlecore(); + + locerror = errflag; + errflag = done = 0; + + return locerror; +} + /**/ mod_export void trashzle(void)