From c56f5aed59a4460d2382ce02eddd0948cab94b17 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 28 Jan 2014 16:12:41 +0000 Subject: 32308: Improve initialising of vi change. Better handling when entering viins on entry to editor. Slightly changed since post to use vi command a. --- Src/Zle/zle_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Src/Zle/zle_main.c') diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 040b7cb83..a2b20df25 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1204,7 +1204,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) * no user operation to indicate this. */ if (openkeymap("main") == openkeymap("viins")) - viinsert(NULL); + viinsert_init(); selectlocalmap(NULL); fixsuffix(); if ((s = getlinknode(bufstack))) { -- cgit v1.2.3 From a8c4ed64ee684227c0dd3142e912f7faca8bd1fb Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Fri, 31 Jan 2014 14:01:12 +0100 Subject: 32314: merge undo events corresponding to vi change in the vi-cmd-mode widget so undo from insert mode is useful again --- ChangeLog | 7 +++++++ Src/Zle/zle_main.c | 11 +++++------ Src/Zle/zle_tricky.c | 3 +-- Src/Zle/zle_utils.c | 5 ++++- Src/Zle/zle_vi.c | 12 +++++++++--- 5 files changed, 26 insertions(+), 12 deletions(-) (limited to 'Src/Zle/zle_main.c') diff --git a/ChangeLog b/ChangeLog index 7c2993486..92ed53cb6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2013-02-27 Oliver Kiddle + + * 32314: Src/Zle/zle_main.c, Src/Zle/zle_tricky.c, + Src/Zle/zle_utils.c, Src/Zle/zle_vi.c: merge undo events + corresponding to vi change in the vi-cmd-mode widget so undo from + insert mode is useful again + 2014-01-30 Barton E. Schaefer * 32322: Completion/Base/Core/_main_complete: display a message diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index a2b20df25..f5aec8403 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -157,10 +157,10 @@ mod_export char *statusline; /**/ int stackhist, stackcs; -/* != 0 if we are making undo records */ +/* position in undo stack from when the current vi change started */ /**/ -int undoing; +zlong vistartchange; /* current modifier status */ @@ -1080,8 +1080,7 @@ zlecore(void) if (invicmdmode() && zlecs > findbol() && (zlecs == zlell || zleline[zlecs] == ZWC('\n'))) DECCS(); - if (undoing) - handleundo(); + handleundo(); } else { errflag = 1; break; @@ -1190,7 +1189,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) zlereadflags = flags; zlecontext = context; histline = curhist; - undoing = 1; + vistartchange = 0; zleline = (ZLE_STRING_T)zalloc(((linesz = 256) + 2) * ZLE_CHAR_SIZE); *zleline = ZWC('\0'); virangeflag = lastcmd = done = zlecs = zlell = mark = 0; @@ -1198,6 +1197,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) viinsbegin = 0; statusline = NULL; selectkeymap("main", 1); + initundo(); /* * If main is linked to the viins keymap, we need to register * explicitly that we're now in vi insert mode as there's @@ -1222,7 +1222,6 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) stackhist = -1; } } - initundo(); if (isset(PROMPTCR)) putc('\r', shout); if (tmout) diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index 9d163ad9e..2689d0fa1 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -611,8 +611,7 @@ docomplete(int lst) active = 1; comprecursive = 0; makecommaspecial(0); - if (undoing) - setlastline(); + setlastline(); /* From the C-code's point of view, we can only use compctl as a default * type of completion. Load it if it hasn't been loaded already and diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index b82e54ce5..61ae85c0b 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -1354,7 +1354,10 @@ handlesuffix(UNUSED(char **args)) /* head of the undo list, and the current position */ -static struct change *changes, *curchange; +/**/ +struct change *curchange; + +static struct change *changes; /* list of pending changes, not yet in the undo system */ diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c index 31f293387..9e9cc2f34 100644 --- a/Src/Zle/zle_vi.c +++ b/Src/Zle/zle_vi.c @@ -107,7 +107,7 @@ startvitext(int im) { startvichange(im); selectkeymap("main", 1); - undoing = 0; + vistartchange = (curchange && curchange->prev) ? curchange->prev->changeno : 0; viinsbegin = zlecs; } @@ -399,7 +399,7 @@ vichange(UNUSED(char **args)) forekill(c2 - zlecs, CUT_RAW); selectkeymap("main", 1); viinsbegin = zlecs; - undoing = 0; + vistartchange = curchange->prev->changeno; } return ret; } @@ -584,7 +584,13 @@ vicmdmode(UNUSED(char **args)) { if (invicmdmode() || selectkeymap("vicmd", 0)) return 1; - undoing = 1; + struct change *current = curchange->prev; + while (current && current->changeno > vistartchange+1) { + current->flags |= CH_PREV; + current = current->prev; + if (!current) break; + current->flags |= CH_NEXT; + } vichgflag = 0; if (zlecs != findbol()) DECCS(); -- cgit v1.2.3 From 2cd3b9ab74a961798362d27094a6d29d7723c171 Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Wed, 5 Feb 2014 21:45:19 +0100 Subject: 32334 (modified so KEEPSUFFIX is unchanged for vi-cmd-mode; based on Jun T: 32324, 32330), 32347, Jun T: 32344, 32349: add split-undo zle widget for configurable breaks in undo sequence --- ChangeLog | 9 ++++++++- Src/Zle/iwidgets.list | 1 + Src/Zle/zle_main.c | 2 +- Src/Zle/zle_utils.c | 26 ++++++++++++++++++++++++++ Src/Zle/zle_vi.c | 8 +------- 5 files changed, 37 insertions(+), 9 deletions(-) (limited to 'Src/Zle/zle_main.c') diff --git a/ChangeLog b/ChangeLog index a5be39298..de6aa34db 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2014-02-05 Oliver Kiddle + + * 32334 (modified so KEEPSUFFIX is unchanged for vi-cmd-mode; based on + Jun T: 32324, 32330), 32347, Jun T: 32344, 32349: Src/Zle/iwidgets.list, + Src/Zle/zle_main.c, Src/Zle/zle_utils.c, Src/Zle/zle_vi.c + add split-undo zle widget for configurable breaks in undo sequence + 2014-02-02 Barton E. Schaefer * unposted: Doc/Zsh/builtins.yo, Doc/Zsh/expn.yo, @@ -20,7 +27,7 @@ unset for better compatibility in emulation modes; for the same reason, remove the readonly flag from $_ -2013-02-27 Oliver Kiddle +2014-01-31 Oliver Kiddle * 32314: Src/Zle/zle_main.c, Src/Zle/zle_tricky.c, Src/Zle/zle_utils.c, Src/Zle/zle_vi.c: merge undo events diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list index 4372fe36e..e3ffe3e8c 100644 --- a/Src/Zle/iwidgets.list +++ b/Src/Zle/iwidgets.list @@ -102,6 +102,7 @@ "self-insert-unmeta", selfinsertunmeta, ZLE_MENUCMP | ZLE_KEEPSUFFIX "send-break", sendbreak, 0 "set-mark-command", setmarkcommand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL +"split-undo", splitundo, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_NOTCOMMAND "spell-word", spellword, 0 "set-local-history", setlocalhistory, 0 "transpose-chars", transposechars, 0 diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index f5aec8403..ed8577bcd 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1189,7 +1189,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) zlereadflags = flags; zlecontext = context; histline = curhist; - vistartchange = 0; + vistartchange = -1; zleline = (ZLE_STRING_T)zalloc(((linesz = 256) + 2) * ZLE_CHAR_SIZE); *zleline = ZWC('\0'); virangeflag = lastcmd = done = zlecs = zlell = mark = 0; diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index 61ae85c0b..9cfa8813d 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -1632,6 +1632,32 @@ viundochange(char **args) return undo(args); } +/**/ +int +splitundo(char **args) +{ + if (vistartchange >= 0) { + mergeundo(); + vistartchange = (curchange && curchange->prev) ? + curchange->prev->changeno : 0; + } + handleundo(); + return 0; +} + +/**/ +void +mergeundo(void) +{ + struct change *current; + for (current = curchange->prev; + current && current->prev && current->changeno > vistartchange+1; + current = current->prev) { + current->flags |= CH_PREV; + current->prev->flags |= CH_NEXT; + } +} + /* * Call a ZLE hook: a user-defined widget called at a specific point * within the line editor. diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c index 9e9cc2f34..79b8cb958 100644 --- a/Src/Zle/zle_vi.c +++ b/Src/Zle/zle_vi.c @@ -584,13 +584,7 @@ vicmdmode(UNUSED(char **args)) { if (invicmdmode() || selectkeymap("vicmd", 0)) return 1; - struct change *current = curchange->prev; - while (current && current->changeno > vistartchange+1) { - current->flags |= CH_PREV; - current = current->prev; - if (!current) break; - current->flags |= CH_NEXT; - } + mergeundo(); vichgflag = 0; if (zlecs != findbol()) DECCS(); -- cgit v1.2.3 From e1bc9d0a44da9c27c5558767cdb75da1a3424a4b Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Wed, 5 Feb 2014 21:55:18 +0100 Subject: 32342: fix overstrike for vi mode and use varying vi commands at line start --- ChangeLog | 3 +++ Src/Zle/zle_main.c | 16 ++++++++-------- Src/Zle/zle_vi.c | 6 ++++-- 3 files changed, 15 insertions(+), 10 deletions(-) (limited to 'Src/Zle/zle_main.c') diff --git a/ChangeLog b/ChangeLog index de6aa34db..b836b0e83 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2014-02-05 Oliver Kiddle + * 32342: Src/Zle/zle_main.c, Src/Zle/zle_vi.c: fix overstrike for vi + mode and use varying vi commands at line start + * 32334 (modified so KEEPSUFFIX is unchanged for vi-cmd-mode; based on Jun T: 32324, 32330), 32347, Jun T: 32344, 32349: Src/Zle/iwidgets.list, Src/Zle/zle_main.c, Src/Zle/zle_utils.c, Src/Zle/zle_vi.c diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index ed8577bcd..b0010fc33 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1198,14 +1198,6 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) statusline = NULL; selectkeymap("main", 1); initundo(); - /* - * If main is linked to the viins keymap, we need to register - * explicitly that we're now in vi insert mode as there's - * no user operation to indicate this. - */ - if (openkeymap("main") == openkeymap("viins")) - viinsert_init(); - selectlocalmap(NULL); fixsuffix(); if ((s = getlinknode(bufstack))) { setline(s, ZSL_TOEND); @@ -1222,6 +1214,14 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) stackhist = -1; } } + /* + * If main is linked to the viins keymap, we need to register + * explicitly that we're now in vi insert mode as there's + * no user operation to indicate this. + */ + if (openkeymap("main") == openkeymap("viins")) + viinsert_init(); + selectlocalmap(NULL); if (isset(PROMPTCR)) putc('\r', shout); if (tmout) diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c index 79b8cb958..994b44fe3 100644 --- a/Src/Zle/zle_vi.c +++ b/Src/Zle/zle_vi.c @@ -79,8 +79,9 @@ static void startvichange(int im) { if (im != -1) { - insmode = im; vichgflag = 1; + if (im > -1) + insmode = im; } if (inrepeat && im != -2) { zmod = lastmod; @@ -92,7 +93,8 @@ startvichange(int im) free(vichgbuf); vichgbuf = (char *)zalloc(vichgbufsz = 16); if (im == -2) { - vichgbuf[0] = 'a'; + vichgbuf[0] = + zlell ? (insmode ? (zlecs < zlell ? 'i' : 'a') : 'R') : 'o'; } else { vichgbuf[0] = lastchar; } -- cgit v1.2.3 From 7e04c1a53ddada7a848753d151e18f9469788b98 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sun, 23 Feb 2014 18:14:12 -0800 Subject: 32427: avoid busy loop on closed descriptors for "zle -F" handlers Also assure the handlers are called on error conditions and document the extra argument that is passed in the error case. --- ChangeLog | 7 +++++++ Doc/Zsh/zle.yo | 47 +++++++++++++++++++++++++++++------------------ Src/Zle/zle_main.c | 39 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 72 insertions(+), 21 deletions(-) (limited to 'Src/Zle/zle_main.c') diff --git a/ChangeLog b/ChangeLog index e215b590c..285d110f6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2014-02-23 Barton E. Schaefer + + * 32427: Doc/Zsh/zle.yo, Src/Zle/zle_main.c: avoid busy loop + on closed descriptors for "zle -F" handlers. Assure that the + handlers are called on error conditions and document the extra + argument that is passed in the error case. + 2014-02-19 Peter Stephenson * 32414: Src/glob.c: improved error message for missing glob diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index 6d3bb4bd0..127b4c45b 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -492,26 +492,35 @@ Only available if your system supports one of the `poll' or `select' system calls; most modern systems do. Installs var(handler) (the name of a shell function) to handle input from -file descriptor var(fd). When zle is attempting to read data, it will -examine both the terminal and the list of handled var(fd)'s. If data -becomes available on a handled var(fd), zle will call var(handler) with -the fd which is ready for reading as the only argument. If the handler -produces output to the terminal, it should call `tt(zle -I)' before doing -so (see below). The handler should not attempt to read from the terminal. -Note that zle makes no attempt to check whether this fd is actually +file descriptor var(fd). Installing a handler for an var(fd) which is +already handled causes the existing handler to be replaced. Any number of +handlers for any number of readable file descriptors may be installed. +Note that zle makes no attempt to check whether this var(fd) is actually readable when installing the handler. The user must make their own arrangements for handling the file descriptor when zle is not active. -If the option tt(-w) is also given, the var(handler) is instead a -line editor widget, typically a shell function made into a widget using -tt(zle -N). In that case var(handler) can use all the facilities of -zle to update the current editing line. Note, however, that as handling -var(fd) takes place at a low level changes to the display will not -automatically appear; the widget should call tt(zle -R) to force redisplay. - -Any number of handlers for any number of readable file descriptors may be -installed. Installing a handler for an var(fd) which is already handled -causes the existing handler to be replaced. +When zle is attempting to read data, it will examine both the terminal and +the list of handled var(fd)'s. If data becomes available on a handled +var(fd), zle calls var(handler) with the fd which is ready for reading +as the first argument. Under normal circumstances this is the only +argument, but if an error was detected, a second argument provides +details: `tt(hup)' for a disconnect, `tt(nval)' for a closed or otherwise +invalid descriptor, or `tt(err)' for any other condition. Systems that +support only the `select' system call always use `tt(err)'. + +If the option tt(-w) is also given, the var(handler) is instead a line +editor widget, typically a shell function made into a widget using +`tt(zle -N)'. In that case var(handler) can use all the facilities of zle +to update the current editing line. Note, however, that as handling var(fd) +takes place at a low level changes to the display will not automatically +appear; the widget should call `tt(zle -R)' to force redisplay. As of this +writing, widget handlers only support a single argument and thus are never +passed a string for error state, so widgets must be prepared to test the +descriptor themselves. + +If either type of handler produces output to the terminal, it should call +`tt(zle -I)' before doing so (see below). Handlers should not attempt to +read from the terminal. If no var(handler) is given, but an var(fd) is present, any handler for that var(fd) is removed. If there is none, an error message is printed @@ -526,7 +535,8 @@ silently return status 1. Note that this feature should be used with care. Activity on one of the var(fd)'s which is not properly handled can cause the terminal to become -unusable. +unusable. Removing an var(fd) handler from within a signal trap may cause +unpredictable behavior. Here is a simple example of using this feature. A connection to a remote TCP port is created using the ztcp command; see @@ -536,6 +546,7 @@ which simply prints out any data which arrives on this connection. Note that `select' will indicate that the file descriptor needs handling if the remote side has closed the connection; we handle that by testing for a failed read. + example(if ztcp pwspc 2811; then tcpfd=$REPLY handler+LPAR()RPAR() { diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index b0010fc33..442c31995 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -525,7 +525,8 @@ raw_getbyte(long do_keytmout, char *cptr) #endif #ifndef HAVE_POLL # ifdef HAVE_SELECT - fd_set foofd; + fd_set foofd, errfd; + FD_ZERO(&errfd); # endif #endif @@ -613,11 +614,14 @@ raw_getbyte(long do_keytmout, char *cptr) if (!errtry) { for (i = 0; i < nwatch; i++) { int fd = watch_fds[i].fd; + if (FD_ISSET(fd, &errfd)) + continue; FD_SET(fd, &foofd); if (fd > fdmax) fdmax = fd; } } + FD_ZERO(&errfd); if (tmout.tp != ZTM_NONE) { expire_tv.tv_sec = tmout.exp100ths / 100; @@ -732,9 +736,10 @@ raw_getbyte(long do_keytmout, char *cptr) Watch_fd lwatch_fd = lwatch_fds + i; if ( # ifdef HAVE_POLL - (fds[i+1].revents & POLLIN) + (fds[i+1].revents & (POLLIN|POLLERR|POLLHUP|POLLNVAL)) # else - FD_ISSET(lwatch_fd->fd, &foofd) + FD_ISSET(lwatch_fd->fd, &foofd) || + FD_ISSET(lwatch_fd->fd, &errfd) # endif ) { /* Handle the fd. */ @@ -765,6 +770,9 @@ raw_getbyte(long do_keytmout, char *cptr) if (fds[i+1].revents & POLLNVAL) zaddlinknode(funcargs, ztrdup("nval")); # endif +# else + if (FD_ISSET(lwatch_fd->fd, &errfd)) + zaddlinknode(funcargs, ztrdup("err")); # endif callhookfunc(lwatch_fd->func, funcargs, 0, NULL); freelinklist(funcargs, freestr); @@ -786,6 +794,31 @@ raw_getbyte(long do_keytmout, char *cptr) for (i = 0; i < lnwatch; i++) zsfree(lwatch_fds[i].func); zfree(lwatch_fds, lnwatch*sizeof(struct watch_fd)); + +# ifdef HAVE_POLL + /* Function may have added or removed handlers */ + nfds = 1 + nwatch; + if (nfds > 1) { + fds = zrealloc(fds, sizeof(struct pollfd) * nfds); + for (i = 0; i < nwatch; i++) { + /* + * This is imperfect because it assumes fds[] and + * watch_fds[] remain in sync, which may be false + * if handlers are shuffled. However, it should + * be harmless (e.g., produce one extra pass of + * the loop) in the event they fall out of sync. + */ + if (fds[i+1].fd == watch_fds[i].fd && + (fds[i+1].revents & (POLLERR|POLLHUP|POLLNVAL))) { + fds[i+1].events = 0; /* Don't poll this */ + } else { + fds[i+1].fd = watch_fds[i].fd; + fds[i+1].events = POLLIN; + } + fds[i+1].revents = 0; + } + } +# endif } } # ifdef HAVE_POLL -- cgit v1.2.3