From 21202e7b95b2b34446fbac34df67205b3889eed2 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sun, 20 Mar 2016 10:30:58 -0700 Subject: 38191: additional re-entrancy checks in reexpandprompt() Do not free global pointers until after promptexpand() in case they are referenced from signal handlers, and check for window size changes during promptexpand(). --- Src/Zle/zle_main.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) (limited to 'Src/Zle/zle_main.c') diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 6e2bfded8..104e5d6c5 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1856,6 +1856,7 @@ void reexpandprompt(void) { static int reexpanding; + static int looping; if (!reexpanding++) { /* @@ -1866,15 +1867,33 @@ reexpandprompt(void) int local_lastval = lastval; lastval = pre_zle_status; - free(lpromptbuf); - lpromptbuf = promptexpand(raw_lp ? *raw_lp : NULL, 1, NULL, NULL, - &pmpt_attr); - rpmpt_attr = pmpt_attr; - free(rpromptbuf); - rpromptbuf = promptexpand(raw_rp ? *raw_rp : NULL, 1, NULL, NULL, - &rpmpt_attr); + do { + /* A new SIGWINCH may arrive while in promptexpand(), causing + * looping to increment. This only happens when a command + * substitution is used in a PROMPT_SUBST prompt, but + * nevertheless keep trying until we see no more changes. + */ + char *new_lprompt, *new_rprompt; + looping = reexpanding; + + new_lprompt = promptexpand(raw_lp ? *raw_lp : NULL, 1, NULL, NULL, + &pmpt_attr); + free(lpromptbuf); + lpromptbuf = new_lprompt; + + if (looping != reexpanding) + continue; + + rpmpt_attr = pmpt_attr; + new_rprompt = promptexpand(raw_rp ? *raw_rp : NULL, 1, NULL, NULL, + &rpmpt_attr); + free(rpromptbuf); + rpromptbuf = new_rprompt; + } while (looping != reexpanding); + lastval = local_lastval; - } + } else + looping = reexpanding; reexpanding--; } -- cgit v1.2.3 From 2b7035d974a69d9a47b1f89f868787a4585386a1 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 4 Apr 2016 14:54:54 +0100 Subject: 38241: ungetkeycmd() needs to unmetafy key string. Use the new function to simplify memory management in prefix handling. Third time lucky. --- Src/Zle/zle_keymap.c | 9 ++------- Src/Zle/zle_main.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) (limited to 'Src/Zle/zle_main.c') diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index 382eb8d41..13fd13844 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -1672,7 +1672,7 @@ getkeybuf(int w) mod_export void ungetkeycmd(void) { - ungetbytes(keybuf, keybuflen); + ungetbytes_unmeta(keybuf, keybuflen); } /* read a command from the current keymap, with widgets */ @@ -1690,17 +1690,12 @@ getkeycmd(void) if(!*seq) return NULL; if(!func) { - int len; - char *pb; - if (++hops == 20) { zerr("string inserting another one too many times"); hops = 0; return NULL; } - pb = unmetafy(ztrdup(str), &len); - ungetbytes(pb, len); - zfree(pb, strlen(str) + 1); + ungetbytes_unmeta(str, strlen(str)); goto sentstring; } if (func == Th(z_executenamedcmd) && !statusline) { diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 104e5d6c5..472e326d1 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -357,6 +357,21 @@ ungetbytes(char *s, int len) ungetbyte(*--s); } +/**/ +void +ungetbytes_unmeta(char *s, int len) +{ + s += len; + while (len--) { + if (len && s[-2] == Meta) { + ungetbyte(*--s ^ 32); + len--; + s--; + } else + ungetbyte(*--s); + } +} + #if defined(pyr) && defined(HAVE_SELECT) static int breakread(int fd, char *buf, int n) -- cgit v1.2.3 From c32bb6a11c460faeaa9fafdb7b1f9cf3d6d10325 Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Sun, 17 Jul 2016 12:09:24 +0200 Subject: 38845: reset region_active before entering zle It was done on exit but before zle-line-finish. Also reword documentation on region to better cover vi mode. --- ChangeLog | 6 ++++++ Doc/Zsh/zle.yo | 17 ++++++++--------- Src/Zle/zle_main.c | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) (limited to 'Src/Zle/zle_main.c') diff --git a/ChangeLog b/ChangeLog index e89a494c5..be387302c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2016-07-17 Oliver Kiddle + + * 38845: Src/Zle/zle_main.c, Doc/Zsh/zle.yo: reset region_active + before entering zle - it was on exit but before zle-line-finish + Also reword documentation on region to better cover vi mode + 2016-07-13 Barton E. Schaefer * 38850: Functions/Zle/add-zle-hook-widget: Simplify indexing diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index f51eadac5..1642c5b15 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -2571,15 +2571,14 @@ When one of the incremental history search widgets is active, the area of the command line matched by the search string or pattern. ) item(tt(region))( -The region between the cursor (point) and the mark as set with -tt(set-mark-command). The region is only highlighted if it is active, -which is the case if tt(set-mark-command) or tt(exchange-point-and-mark) -has been called and the line has not been subsequently modified. The -region can be deactivated by calling tt(set-mark-command) with a -negative numeric argument, or reactivated by calling -tt(exchange-point-and-mark) with a zero numeric argument. Note -that whether or not the region is active has no effect on its -use within widgets, it simply determines whether it is highlighted. +The currently selected text. In emacs terminology, this is referred to as +the region and is bounded by the cursor (point) and the mark. The region +is only highlighted if it is active, which is the case after the mark +is modified with tt(set-mark-command) or tt(exchange-point-and-mark). +Note that whether or not the region is active has no effect on its +use within emacs style widgets, it simply determines whether it is +highlighted. In vi mode, the region corresponds to selected text in +visual mode. ) cindex(special characters, highlighting) cindex(highlighting, special characters) diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 472e326d1..ac31d4e09 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1159,7 +1159,6 @@ zlecore(void) } - region_active = 0; popheap(); } @@ -1292,6 +1291,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) lastcol = -1; initmodifier(&zmod); prefixflag = 0; + region_active = 0; zrefresh(); -- cgit v1.2.3 From 8d7b9d013ddb3f8f065ffc881f927cbe4790abef Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Wed, 27 Jul 2016 08:53:14 +0000 Subject: 38927: zle-line-pre-redraw: Set $WIDGET like other special widgets do. --- ChangeLog | 3 +++ Src/Zle/zle_main.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'Src/Zle/zle_main.c') diff --git a/ChangeLog b/ChangeLog index 9153ff197..d650272ad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2016-07-28 Daniel Shahaf + * 38927: Src/Zle/zle_main.c: zle-line-pre-redraw: Set $WIDGET + like other special widgets do. + * unposted: Functions/Misc/add-zle-hook-widget, Functions/Misc/add-zsh-hook: Avoid $0 for POSIX_ARGZERO compatibility. diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index ac31d4e09..9a83d4141 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1054,7 +1054,7 @@ void redrawhook(void) args[0] = initthingy->nam; args[1] = NULL; incompfunc = 0; - execzlefunc(initthingy, args, 0); + execzlefunc(initthingy, args, 1); incompfunc = old_incompfunc; unrefthingy(initthingy); unrefthingy(lbindk); -- cgit v1.2.3 From 5cf2ffb327faf84b73beb812ff2f7e9bf08e7ecf Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Mon, 26 Sep 2016 11:55:33 +0200 Subject: Call the pre-redraw hook if there is text in the buffer on init --- ChangeLog | 6 ++++++ Src/Zle/zle_main.c | 14 +++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'Src/Zle/zle_main.c') diff --git a/ChangeLog b/ChangeLog index 8450407c8..b49289b63 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2016-09-30 Mikael Magnusson + + * 39452 + comment from 39432: Src/Zle/zle_main.c: Call the + pre-redraw hook if there is text in the buffer on init (from + popping or zle-line-init setting $BUFFER) + 2016-09-30 Oliver Kiddle * 39514: Completion/Unix/Command/_git: handle --git-dir diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 9a83d4141..0bdd82ba4 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1162,7 +1162,16 @@ zlecore(void) popheap(); } -/* Read a line. It is returned metafied. */ +/* Read a line. It is returned metafied. + * + * Parameters: + * - lp: left prompt, e.g., $PS1 + * - rp: right prompt, e.g., $RPS1 + * - flags: ZLRF_* flags (I think), see zlereadflags + * - context: ZLCON_* flags (I think), see zlecontext + * - init: "zle-line-init" + * - finish: "zle-line-finish" + */ /**/ char * @@ -1299,6 +1308,9 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) zlecallhook(init, NULL); + if (zleline && *zleline) + redrawhook(); + if ((bracket = getaparam("zle_bracketed_paste")) && arrlen(bracket) == 2) fputs(*bracket, shout); -- cgit v1.2.3 From 4ab3fcc90d928d200f9e70c81189079c3316b42d Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 3 Oct 2016 13:43:20 +0100 Subject: 39545: Add some missing unqueue_signals(). All of these are added simply to fit existing logic in other branches. --- ChangeLog | 5 +++++ Src/Zle/computil.c | 1 + Src/Zle/zle_main.c | 1 + Src/builtin.c | 3 +++ Src/exec.c | 3 +++ Src/hist.c | 1 + Src/init.c | 4 +++- Src/mem.c | 8 ++++++-- Src/module.c | 1 + Src/params.c | 2 ++ Src/prompt.c | 4 +++- 11 files changed, 29 insertions(+), 4 deletions(-) (limited to 'Src/Zle/zle_main.c') diff --git a/ChangeLog b/ChangeLog index a1c4e60e3..a68dfaf59 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2016-10-03 Peter Stephenson + * 39545: Src/builtin.c, Src/exec.c, Src/hist.c, Src/init.c, + Src/mem.c, Src/module.c, Src/params.c, Src/prompt.c, + Src/Zle/computil.c, Src/Zle/zle_main.c: Add some missing + unqueue_signals(). + * 39521: Src/exec.c, Src/zsh.h, Test/A01grammar.ztst: Refactor start of execcmd(). This allows execpline2() easier access to the state at the start of execuation. diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c index 27b78cd61..e9bad1cab 100644 --- a/Src/Zle/computil.c +++ b/Src/Zle/computil.c @@ -4865,6 +4865,7 @@ bin_compfiles(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) } queue_signals(); if (!(tmp = getaparam(args[1]))) { + unqueue_signals(); zwarnnam(nam, "unknown parameter: %s", args[1]); return 0; } diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 0bdd82ba4..0b3b1fcf4 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1631,6 +1631,7 @@ bin_vared(char *name, char **args, Options ops, UNUSED(int func)) return 1; } else if (v) { if (*s) { + unqueue_signals(); zwarnnam(name, "not an identifier: `%s'", args[0]); return 1; } diff --git a/Src/builtin.c b/Src/builtin.c index 60dc07f25..a274ff791 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1489,6 +1489,7 @@ bin_fc(char *nam, char **argv, Options ops, int func) } if (zleactive) { + unqueue_signals(); zwarnnam(nam, "no interactive history within ZLE"); return 1; } @@ -2808,6 +2809,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func) return 0; } if (off & PM_TIED) { + unqueue_signals(); zerrnam(name, "use unset to remove tied variables"); return 1; } @@ -3138,6 +3140,7 @@ bin_functions(char *name, char **argv, Options ops, int func) queue_signals(); for (q = mathfuncs; q; q = q->next) { if (!strcmp(q->name, funcname)) { + unqueue_signals(); zwarnnam(name, "-M %s: function already exists", funcname); zsfree(p->name); diff --git a/Src/exec.c b/Src/exec.c index a4294288b..9890286b2 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1795,6 +1795,8 @@ execpline(Estate state, wordcode slcode, int how, int last1) deletejob(jn, 0); thisjob = pj; } + else + unqueue_signals(); if ((slflags & WC_SUBLIST_NOT) && !errflag) lastval = !lastval; } @@ -5556,6 +5558,7 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name) if (!cont) { if (ou) zfree(ou, ouu); + unqueue_signals(); return; } wrap = wrap->next; diff --git a/Src/hist.c b/Src/hist.c index 5fc40bd67..eebd7dcde 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -653,6 +653,7 @@ histsubchar(int c) (c == '}' || c == ';' || c == '\'' || c == '"' || c == '`')) { /* Neither event nor word designator, no expansion */ safeinungetc(c); + unqueue_signals(); return bangchar; } *ptr = 0; diff --git a/Src/init.c b/Src/init.c index 3dea179b9..c12043b88 100644 --- a/Src/init.c +++ b/Src/init.c @@ -1442,8 +1442,10 @@ sourcehome(char *s) queue_signals(); if (EMULATION(EMULATE_SH|EMULATE_KSH) || !(h = getsparam_u("ZDOTDIR"))) { h = home; - if (!h) + if (!h) { + unqueue_signals(); return; + } } { diff --git a/Src/mem.c b/Src/mem.c index 021dad573..db311efbd 100644 --- a/Src/mem.c +++ b/Src/mem.c @@ -903,11 +903,15 @@ memory_validate(Heapid heap_id) queue_signals(); for (h = heaps; h; h = h->next) { - if (h->heap_id == heap_id) + if (h->heap_id == heap_id) { + unqueue_signals(); return 0; + } for (hs = heaps->sp; hs; hs = hs->next) { - if (hs->heap_id == heap_id) + if (hs->heap_id == heap_id) { + unqueue_signals(); return 0; + } } } diff --git a/Src/module.c b/Src/module.c index 46a7d7746..41f142adb 100644 --- a/Src/module.c +++ b/Src/module.c @@ -2242,6 +2242,7 @@ load_module(char const *name, Feature_enables enablesarr, int silent) return 0; } if (m->node.flags & MOD_BUSY) { + unqueue_signals(); zerr("circular dependencies for module ;%s", name); return 1; } diff --git a/Src/params.c b/Src/params.c index e11510246..1418021aa 100644 --- a/Src/params.c +++ b/Src/params.c @@ -2803,6 +2803,7 @@ assignsparam(char *s, char *val, int flags) zerr("read-only variable: %s", v->pm->node.nam); *ss = '['; zsfree(val); + unqueue_signals(); return NULL; } flags &= ~ASSPM_WARN_CREATE; @@ -3117,6 +3118,7 @@ setnparam(char *s, mnumber val) if (!(v = getvalue(&vbuf, &t, 1))) { DPUTS(!v, "BUG: value not found for new parameter"); /* errflag |= ERRFLAG_ERROR; */ + unqueue_signals(); return NULL; } if (!was_unset && isset(WARNCREATEGLOBAL) && locallevel > forklevel) diff --git a/Src/prompt.c b/Src/prompt.c index d4f389809..ee77c8bc8 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -491,8 +491,10 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep) if (!arg) arg++; queue_signals(); - if (!(hostnam = getsparam("HOST"))) + if (!(hostnam = getsparam("HOST"))) { + unqueue_signals(); break; + } if (arg < 0) { for (ss = hostnam + strlen(hostnam); ss > hostnam; ss--) if (ss[-1] == '.' && !++arg) -- cgit v1.2.3 From b71abea40f491726f96ea26143306ec27aa611ee Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Mon, 3 Oct 2016 09:35:14 -0700 Subject: 39547: handle zero delta in calc_timeout() --- ChangeLog | 4 ++++ Src/Zle/zle_main.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'Src/Zle/zle_main.c') diff --git a/ChangeLog b/ChangeLog index a68dfaf59..81d31c969 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2016-10-03 Barton E. Schaefer + + * 39547: Src/Zle/zle_main.c: handle zero delta in calc_timeout() + 2016-10-03 Peter Stephenson * 39545: Src/builtin.c, Src/exec.c, Src/hist.c, Src/init.c, diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 0b3b1fcf4..4b47d6072 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -471,7 +471,7 @@ calc_timeout(struct ztmout *tmoutp, long do_keytmout) tfdat = (Timedfn)getdata(tfnode); diff = tfdat->when - time(NULL); - if (diff < 0) { + if (diff <= 0) { /* Already due; call it and rescan. */ tfdat->func(); continue; -- cgit v1.2.3 From ccc0b6f8a625357cbae9dfd4a685b9323e09c13f Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Mon, 3 Oct 2016 09:40:39 -0700 Subject: 39550: reset signal queue in recursiveedit() --- ChangeLog | 2 ++ Src/Zle/zle_main.c | 6 ++++++ 2 files changed, 8 insertions(+) (limited to 'Src/Zle/zle_main.c') diff --git a/ChangeLog b/ChangeLog index a7dfa2e3c..125121037 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2016-10-03 Barton E. Schaefer + * 39550: Src/Zle/zle_main.c: reset signal queue in recursiveedit() + * 39548: Src/signals.c, Src/signals.h: DEBUG for queueing_enabled * 39547: Src/Zle/zle_main.c: handle zero delta in calc_timeout() diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 4b47d6072..04b93575f 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1868,11 +1868,17 @@ int recursiveedit(UNUSED(char **args)) { int locerror; + int q = queue_signal_level(); + + /* zlecore() expects to be entered with signal queue disabled */ + dont_queue_signals(); redrawhook(); zrefresh(); zlecore(); + restore_queue_signals(q); + locerror = errflag ? 1 : 0; errflag = done = eofsent = 0; -- cgit v1.2.3 From 7b8f63871372e0cd01e9ed9bf313a8a96d9a1965 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sun, 13 Nov 2016 11:04:25 -0800 Subject: 39933: more of zlecallhook() in redrawhook() add commentary on some of the differences --- ChangeLog | 3 +++ Src/Zle/zle_main.c | 19 +++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'Src/Zle/zle_main.c') diff --git a/ChangeLog b/ChangeLog index e8740b8c4..8345fb23f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2016-11-13 Barton E. Schaefer + * 39933: Src/Zle/zle_main.c: more of zlecallhook() in redrawhook(), + add commentary on some of the differences + * 39929: Doc/Zsh/zle.yo: clarify execute{,-last}-named-cmd 2016-11-12 Barton E. Schaefer diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 04b93575f..96b631eeb 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1041,28 +1041,43 @@ getrestchar(int inchar, char *outstr, int *outcount) #endif /**/ -void redrawhook(void) +void +redrawhook(void) { Thingy initthingy; if ((initthingy = rthingy_nocreate("zle-line-pre-redraw"))) { + /* Duplicating most of zlecallhook() to save additional state */ + int saverrflag = errflag, savretflag = retflag; int lastcmd_prev = lastcmd; int old_incompfunc = incompfunc; char *args[2]; Thingy lbindk_save = lbindk, bindk_save = bindk; + refthingy(lbindk_save); refthingy(bindk_save); args[0] = initthingy->nam; args[1] = NULL; + + /* The generic redraw hook cannot be a completion function, so + * temporarily reset state for special variable handling etc. + */ incompfunc = 0; execzlefunc(initthingy, args, 1); incompfunc = old_incompfunc; + + /* Restore errflag and retflag as zlecallhook() does */ + errflag = saverrflag | (errflag & ERRFLAG_INT); + retflag = savretflag; + unrefthingy(initthingy); unrefthingy(lbindk); unrefthingy(bindk); lbindk = lbindk_save; bindk = bindk_save; + /* we can't set ZLE_NOTCOMMAND since it's not a legit widget, so - * restore lastcmd manually so that we don't mess up the global state */ + * restore lastcmd manually so that we don't mess up the global state + */ lastcmd = lastcmd_prev; } } -- cgit v1.2.3 From cbb9ca3dfbb6ecaa8b5099a3302b196a91a026d8 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sun, 13 Nov 2016 15:52:09 -0800 Subject: 39934: if a widget execution fails, try to execute a corresponding immortal widget instead. --- ChangeLog | 3 +++ Src/Zle/zle_main.c | 18 +++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) (limited to 'Src/Zle/zle_main.c') diff --git a/ChangeLog b/ChangeLog index 8345fb23f..586194454 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2016-11-13 Barton E. Schaefer + * 39934: Src/Zle/zle_main.c: if a widget execution fails, try to + execute a corresponding immortal widget instead. + * 39933: Src/Zle/zle_main.c: more of zlecallhook() in redrawhook(), add commentary on some of the differences diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 96b631eeb..1652b7cd4 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1368,6 +1368,16 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) return s; } +/**/ +static int +execimmortal(Thingy func, char **args) +{ + Thingy immortal = rthingy_nocreate(dyncat(".", func->nam)); + if (immortal) + return execzlefunc(immortal, args, 0); + return 1; +} + /* * Execute a widget. The third argument indicates that the global * variable bindk should be set temporarily so that WIDGET etc. @@ -1389,7 +1399,7 @@ execzlefunc(Thingy func, char **args, int set_bindk) remetafy = 1; } - if(func->flags & DISABLED) { + if (func->flags & DISABLED) { /* this thingy is not the name of a widget */ char *nm = nicedup(func->nam, 0); char *msg = tricat("No such widget `", nm, "'"); @@ -1397,7 +1407,7 @@ execzlefunc(Thingy func, char **args, int set_bindk) zsfree(nm); showmsg(msg); zsfree(msg); - ret = 1; + ret = execimmortal(func, args); } else if((w = func->widget)->flags & (WIDGET_INT|WIDGET_NCOMP)) { int wflags = w->flags; @@ -1461,7 +1471,7 @@ execzlefunc(Thingy func, char **args, int set_bindk) zsfree(nm); showmsg(msg); zsfree(msg); - ret = 1; + ret = execimmortal(func, args); } else { int osc = sfcontext, osi = movefd(0); int oxt = isset(XTRACE); @@ -1483,6 +1493,8 @@ execzlefunc(Thingy func, char **args, int set_bindk) opts[XTRACE] = oxt; sfcontext = osc; endparamscope(); + if (errflag == ERRFLAG_ERROR && !(ret = execimmortal(func, args))) + errflag &= ~ERRFLAG_ERROR; lastcmd = w->flags & ~(WIDGET_INUSE|WIDGET_FREE); if (inuse) { w->flags &= WIDGET_INUSE|WIDGET_FREE; -- cgit v1.2.3 From cb5f100bd38a3b21739897fb4236db0700b39477 Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Sun, 20 Nov 2016 23:54:45 +0100 Subject: 39986, 39989: improve handling of vi-repeat-change Save previous vi change and throw away a new change that fails. Add zle -f vichange to allow shell widget to be a single change. Fix repeat of command where numeric arguments were multiplied. --- ChangeLog | 7 +++ Doc/Zsh/zle.yo | 7 +++ Functions/Zle/vi-pipe | 3 ++ Src/Zle/zle.h | 14 ++++++ Src/Zle/zle_keymap.c | 2 +- Src/Zle/zle_main.c | 34 +++++++++++-- Src/Zle/zle_misc.c | 8 ++- Src/Zle/zle_thingy.c | 11 +++- Src/Zle/zle_utils.c | 1 + Src/Zle/zle_vi.c | 137 +++++++++++++++++++++++--------------------------- Test/X02zlevi.ztst | 10 ++-- 11 files changed, 147 insertions(+), 87 deletions(-) (limited to 'Src/Zle/zle_main.c') diff --git a/ChangeLog b/ChangeLog index 1095a1e5c..24fb8a3f3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2016-11-20 Oliver Kiddle + * 39986, 39989: Src/Zle/zle.h, Src/Zle/zle_keymap.c, + Src/Zle/zle_main.c, Src/Zle/zle_misc.c, Src/Zle/zle_thingy.c, + Src/Zle/zle_utils.c, Src/Zle/zle_vi.c, Test/X02zlevi.ztst, + Doc/Zsh/zle.yo, Functions/Zle/vi-pipe: make vi-repeat-change + work better with shell based widgets and save old change + when recording a new change in case the new one fails + * 39974: Completion/Unix/Command/_ssh: complete shared libraries for -e and -s options to ssh-add diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index fe6a7e93b..ff3144802 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -479,6 +479,13 @@ tt(kill) for indicating that text has been killed into the cutbuffer. When repeatedly invoking a kill widget, text is appended to the cutbuffer instead of replacing it, but when wrapping such widgets, it is necessary to call `tt(zle -f kill)' to retain this effect. + +tt(vichange) for indicating that the widget represents a vi change that +can be repeated as a whole with `tt(vi-repeat-change)'. The flag should be set +early in the function before inspecting the value of tt(NUMERIC) or invoking +other widgets. This has no effect for a widget invoked from insert mode. If +insert mode is active when the widget finishes, the change extends until next +returning to command mode. ) cindex(completion widgets, creating) item(tt(-C) var(widget) var(completion-widget) var(function))( diff --git a/Functions/Zle/vi-pipe b/Functions/Zle/vi-pipe index c32e64a59..1729cb6e1 100644 --- a/Functions/Zle/vi-pipe +++ b/Functions/Zle/vi-pipe @@ -12,6 +12,9 @@ setopt localoptions noksharrays autoload -Uz read-from-minibuffer local _save_cut="$CUTBUFFER" REPLY +# mark this widget as a vi change so it can be repeated as a whole +zle -f vichange + # force movement to default to line mode (( REGION_ACTIVE )) || zle -U V # Use the standard vi-change to accept a vi motion. diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h index e9b14281d..8f92e5611 100644 --- a/Src/Zle/zle.h +++ b/Src/Zle/zle.h @@ -284,6 +284,20 @@ struct change { #define CH_NEXT (1<<0) /* next structure is also part of this change */ #define CH_PREV (1<<1) /* previous structure is also part of this change */ +/* vi change handling for vi-repeat-change */ + +/* + * Examination of the code suggests vichgbuf is consistently tied + * to raw byte input, so it is left as a character array rather + * than turned into wide characters. In particular, when we replay + * it we use ungetbytes(). + */ +struct vichange { + struct modifier mod; /* value of zmod associated with vi change */ + char *buf; /* bytes for keys that make up the vi command */ + int bufsz, bufptr; /* allocated and in use sizes of buf */ +}; + /* known thingies */ #define Th(X) (&thingies[X]) diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index 24e8d1964..04eb70675 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -1634,7 +1634,7 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp) unmetafy(keybuf + lastlen, &keybuflen); ungetbytes(keybuf+lastlen, keybuflen); if(vichgflag) - vichgbufptr -= keybuflen; + curvichg.bufptr -= keybuflen; keybuf[keybuflen = lastlen] = 0; } *funcp = func; diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 1652b7cd4..938dc0e29 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -924,13 +924,13 @@ getbyte(long do_keytmout, int *timeout) ret = STOUC(cc); } /* - * vichgbuf is raw bytes, not wide characters, so is dealt + * curvichg.buf is raw bytes, not wide characters, so is dealt * with here. */ if (vichgflag) { - if (vichgbufptr == vichgbufsz) - vichgbuf = realloc(vichgbuf, vichgbufsz *= 2); - vichgbuf[vichgbufptr++] = ret; + if (curvichg.bufptr == curvichg.bufsz) + curvichg.buf = realloc(curvichg.buf, curvichg.bufsz *= 2); + curvichg.buf[curvichg.bufptr++] = ret; } errno = old_errno; return lastchar = ret; @@ -1260,6 +1260,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) *zleline = ZWC('\0'); virangeflag = lastcmd = done = zlecs = zlell = mark = yankb = yanke = 0; vichgflag = 0; + viinrepeat = 0; viinsbegin = 0; statusline = NULL; selectkeymap("main", 1); @@ -1389,6 +1390,8 @@ int execzlefunc(Thingy func, char **args, int set_bindk) { int r = 0, ret = 0, remetafy = 0; + int nestedvichg = vichgflag; + int isrepeat = (viinrepeat == 3); Widget w; Thingy save_bindk = bindk; @@ -1398,6 +1401,8 @@ execzlefunc(Thingy func, char **args, int set_bindk) unmetafy_line(); remetafy = 1; } + if (isrepeat) + viinrepeat = 2; if (func->flags & DISABLED) { /* this thingy is not the name of a widget */ @@ -1523,6 +1528,25 @@ execzlefunc(Thingy func, char **args, int set_bindk) CCRIGHT(); if (remetafy) metafy_line(); + + /* if this widget constituted the vi change, end it */ + if (vichgflag == 2 && !nestedvichg) { + if (invicmdmode()) { + if (ret) { + free(curvichg.buf); + } else { + if (lastvichg.buf) + free(lastvichg.buf); + lastvichg = curvichg; + } + vichgflag = 0; + curvichg.buf = NULL; + } else + vichgflag = 1; /* vi change continues while in insert mode */ + } + if (isrepeat) + viinrepeat = !invicmdmode(); + return ret; } @@ -2230,7 +2254,7 @@ finish_(UNUSED(Module m)) cleanup_keymaps(); deletehashtable(thingytab); - zfree(vichgbuf, vichgbufsz); + zfree(lastvichg.buf, lastvichg.bufsz); zfree(kungetbuf, kungetsz); free_isrch_spots(); if (rdstrs) diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index fbd40cd03..898b552de 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -609,8 +609,10 @@ viputbefore(UNUSED(char **args)) int n = zmult; startvichange(-1); - if (n < 0 || zmod.flags & MOD_NULL) + if (n < 0) return 1; + if (zmod.flags & MOD_NULL) + return 0; if (zmod.flags & MOD_VIBUF) kctbuf = &vibuf[zmod.vibuf]; else @@ -630,8 +632,10 @@ viputafter(UNUSED(char **args)) int n = zmult; startvichange(-1); - if (n < 0 || zmod.flags & MOD_NULL) + if (n < 0) return 1; + if (zmod.flags & MOD_NULL) + return 0; if (zmod.flags & MOD_VIBUF) kctbuf = &vibuf[zmod.vibuf]; else diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c index 2d4674785..c7092854a 100644 --- a/Src/Zle/zle_thingy.c +++ b/Src/Zle/zle_thingy.c @@ -678,7 +678,16 @@ bin_zle_flags(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) else if (!strcmp(*flag, "keepsuffix")) w->flags |= ZLE_KEEPSUFFIX; */ - else { + else if (!strcmp(*flag, "vichange")) { + if (invicmdmode()) { + startvichange(-1); + if (zmod.flags & (MOD_MULT|MOD_TMULT)) { + Param pm = (Param) paramtab->getnode(paramtab, "NUMERIC"); + if (pm && pm->node.flags & PM_SPECIAL) + pm->node.flags &= ~PM_UNSET; + } + } + } else { zwarnnam(name, "invalid flag `%s' given to zle -f", *flag); ret = 1; } diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index 4007c1112..c6df3d89c 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -1704,6 +1704,7 @@ mergeundo(void) current->flags |= CH_PREV; current->prev->flags |= CH_NEXT; } + vistartchange = -1; } /* diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c index fc0e49b32..e0923db3e 100644 --- a/Src/Zle/zle_vi.c +++ b/Src/Zle/zle_vi.c @@ -45,46 +45,41 @@ int wordflag; /**/ int vilinerange; -/* last vi change buffer, for vi change repetition */ +/* + * lastvichg: last vi change buffer, for vi change repetition + * curvichg: current incomplete vi change + */ + +/**/ +struct vichange lastvichg, curvichg; /* - * vichgbufsz: Allocated size of vichgbuf. - * vichgbufptr: Length in use. - * vichgflag: true whilst inputting a vi normal mode; causes it to be - * accumulated in vichgbuf, incrementing vichgbufptr. + * true whilst a vi change is active causing keys to be + * accumulated in curvichg.buf + * first set to 2 and when the initial widget finishes, reduced to 1 if + * in insert mode implying that the change continues until returning to + * normal mode */ /**/ -int vichgbufsz, vichgbufptr, vichgflag; +int vichgflag; /* - * The bytes that make up the current vi command. See vichgbuf* above. - * - * Examination of the code suggests vichgbuf is consistently tied - * to raw byte input, so it is left as a character array rather - * than turned into wide characters. In particular, when we replay - * it we use ungetbytes(). + * analogous to vichgflag for a repeated change with the value following + * a similar pattern (is 3 until first repeated widget starts) */ + /**/ -char *vichgbuf; +int viinrepeat; /* point where vi insert mode was last entered */ /**/ int viinsbegin; -/* value of zmod associated with vi change */ -static struct modifier lastmod; - -/* - * inrepeat: current widget is the vi change being repeated - * vichgrepeat: nested widget call within a repeat - */ -static int inrepeat, vichgrepeat; - /** * im: >= 0: is an insertmode - * -1: skip setting insert mode + * -1: skip setting insert/overwrite mode * -2: entering viins at start of editing from clean --- don't use * inrepeat or keybuf, synthesise an entry to insert mode. * Note that zmult is updated so this should be called before zmult is used. @@ -94,30 +89,27 @@ static int inrepeat, vichgrepeat; void startvichange(int im) { - if (im != -1) { - vichgflag = 1; - if (im > -1) - insmode = im; - } - if (inrepeat && im != -2) { - zmod = lastmod; - inrepeat = vichgflag = 0; - vichgrepeat = 1; - } else { - lastmod = zmod; - if (vichgbuf) - free(vichgbuf); - vichgbuf = (char *)zalloc(vichgbufsz = 16 + keybuflen); + if (im > -1) + insmode = im; + if (viinrepeat && im != -2) { + zmod = lastvichg.mod; + vichgflag = 0; + } else if (!vichgflag) { + curvichg.mod = zmod; + if (curvichg.buf) + free(curvichg.buf); + curvichg.buf = (char *)zalloc(curvichg.bufsz = 16 + keybuflen); if (im == -2) { - vichgbuf[0] = + vichgflag = 1; + curvichg.buf[0] = zlell ? (insmode ? (zlecs < zlell ? 'i' : 'a') : 'R') : 'o'; - vichgbuf[1] = '\0'; - vichgbufptr = 1; + curvichg.buf[1] = '\0'; + curvichg.bufptr = 1; } else { - strcpy(vichgbuf, keybuf); - unmetafy(vichgbuf, &vichgbufptr); + vichgflag = 2; + strcpy(curvichg.buf, keybuf); + unmetafy(curvichg.buf, &curvichg.bufptr); } - vichgrepeat = 0; } } @@ -226,10 +218,13 @@ getvirange(int wf) */ if ((k2 == bindk) ? dovilinerange() : execzlefunc(k2, zlenoargs, 1)) ret = -1; - if(vichgrepeat) + if (viinrepeat) zmult = mult1; - else + else { zmult = mult1 * zmod.tmult; + if (vichgflag == 2) + curvichg.mod.mult = zmult; + } } while(prefixflag && !ret); wordflag = 0; selectlocalmap(NULL); @@ -401,7 +396,6 @@ videlete(UNUSED(char **args)) vifirstnonblank(zlenoargs); } } - vichgflag = 0; return ret; } @@ -518,7 +512,6 @@ viyank(UNUSED(char **args)) cut(zlecs, c2 - zlecs, CUT_YANK); ret = 0; } - vichgflag = 0; /* cursor now at the start of the range yanked. For line mode * restore the column position */ if (vilinerange && lastcol != -1) { @@ -593,8 +586,7 @@ vireplace(UNUSED(char **args)) * a change, we always read the argument normally, even if the count * * was bad. When recording a change for repeating, and a bad count is * * given, we squash the repeat buffer to avoid repeating the partial * - * command; we've lost the previous change, but that can't be avoided * - * without a rewrite of the repeat code. */ + * command. */ /**/ int @@ -644,18 +636,12 @@ vireplacechars(UNUSED(char **args)) /* check argument range */ if (n < 1 || fail) { - if(vichgrepeat) + if (viinrepeat) vigetkey(); - if(vichgflag) { - free(vichgbuf); - vichgbuf = NULL; - vichgflag = 0; - } return 1; } /* get key */ if((ch = vigetkey()) == ZLEEOF) { - vichgflag = 0; return 1; } /* do change */ @@ -682,7 +668,6 @@ vireplacechars(UNUSED(char **args)) zleline[zlecs++] = ch; zlecs--; } - vichgflag = 0; return 0; } @@ -693,7 +678,16 @@ vicmdmode(UNUSED(char **args)) if (invicmdmode() || selectkeymap("vicmd", 0)) return 1; mergeundo(); - vichgflag = 0; + insmode = unset(OVERSTRIKE); + if (vichgflag == 1) { + vichgflag = 0; + if (lastvichg.buf) + free(lastvichg.buf); + lastvichg = curvichg; + curvichg.buf = NULL; + } + if (viinrepeat == 1) + viinrepeat = 0; if (zlecs != findbol()) DECCS(); return 0; @@ -748,7 +742,6 @@ vioperswapcase(UNUSED(char **args)) vifirstnonblank(); #endif } - vichgflag = 0; return ret; } @@ -771,7 +764,6 @@ viupcase(UNUSED(char **args)) zlecs = oldcs; ret = 0; } - vichgflag = 0; return ret; } @@ -794,7 +786,6 @@ vidowncase(UNUSED(char **args)) zlecs = oldcs; ret = 0; } - vichgflag = 0; return ret; } @@ -803,23 +794,23 @@ int virepeatchange(UNUSED(char **args)) { /* make sure we have a change to repeat */ - if (!vichgbuf || vichgflag || virangeflag) + if (!lastvichg.buf || vichgflag || virangeflag) return 1; /* restore or update the saved count and buffer */ if (zmod.flags & MOD_MULT) { - lastmod.mult = zmod.mult; - lastmod.flags |= MOD_MULT; + lastvichg.mod.mult = zmod.mult; + lastvichg.mod.flags |= MOD_MULT; } if (zmod.flags & MOD_VIBUF) { - lastmod.vibuf = zmod.vibuf; - lastmod.flags = (lastmod.flags & ~MOD_VIAPP) | + lastvichg.mod.vibuf = zmod.vibuf; + lastvichg.mod.flags = (lastvichg.mod.flags & ~MOD_VIAPP) | MOD_VIBUF | (zmod.flags & MOD_VIAPP); - } else if (lastmod.flags & MOD_VIBUF && - lastmod.vibuf >= 27 && lastmod.vibuf <= 34) - lastmod.vibuf++; /* for "1 to "8 advance to next buffer */ + } else if (lastvichg.mod.flags & MOD_VIBUF && + lastvichg.mod.vibuf >= 27 && lastvichg.mod.vibuf <= 34) + lastvichg.mod.vibuf++; /* for "1 to "8 advance to next buffer */ /* repeat the command */ - inrepeat = 1; - ungetbytes(vichgbuf, vichgbufptr); + viinrepeat = 3; + ungetbytes(lastvichg.buf, lastvichg.bufptr); return 0; } @@ -835,10 +826,8 @@ viindent(UNUSED(char **args)) region_active = 2; /* get the range */ if ((c2 = getvirange(0)) == -1) { - vichgflag = 0; return 1; } - vichgflag = 0; /* must be a line range */ if (!vilinerange) { zlecs = oldcs; @@ -873,10 +862,8 @@ viunindent(UNUSED(char **args)) region_active = 2; /* get the range */ if ((c2 = getvirange(0)) == -1) { - vichgflag = 0; return 1; } - vichgflag = 0; /* must be a line range */ if (!vilinerange) { zlecs = oldcs; diff --git a/Test/X02zlevi.ztst b/Test/X02zlevi.ztst index c19573241..d3b533490 100644 --- a/Test/X02zlevi.ztst +++ b/Test/X02zlevi.ztst @@ -140,6 +140,12 @@ >BUFFER: xxe xxx xxxee >CURSOR: 10 + zletest $'one two three four five six seven eight\e.03d2wk.1.' +0:numeric args to both action and movement are multiplied (and saved for any repeat) +>BUFFER: eight +>seven eight +>CURSOR: 0 + zletest $'yankee doodle\ebhDyy0"1P' 0:paste register 1 to get last deletion >BUFFER: doodleyankee @@ -262,10 +268,8 @@ print -u $ZTST_fd 'This test may hang the shell when it fails...' zletest $'worm\erdhd..' 0:use of vi-repeat as the motion and repeat after a failed change ->BUFFER: word +>BUFFER: wodd >CURSOR: 2 -F:For vi compatibility, "." should repeat the "rd" change after "d." -F:Update result to ">BUFFER: wodd" if compatibility is repaired. zpty_run 'bindkey "^_" undo' zletest $'undoc\037e' -- cgit v1.2.3 From c0f95d07e7be34a30047a8202aeb01b864600151 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Wed, 23 Nov 2016 18:15:17 -0800 Subject: unposted: clear ERRFLAG_ERROR before invoking immortal widget (cf. 39934) Updates commit cbb9ca3d --- ChangeLog | 5 +++++ Src/Zle/zle_main.c | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'Src/Zle/zle_main.c') diff --git a/ChangeLog b/ChangeLog index a1a4a0850..58ed68801 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2016-11-23 Bart Schaefer + + * unposted: Src/Zle/zle_main.c: clear ERRFLAG_ERROR before + invoking immortal widget (cf. 39934) + 2016-11-23 Oliver Kiddle * unposted: Test/Y03arguments.ztst: partial match test case diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 938dc0e29..15ea79643 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1498,8 +1498,12 @@ execzlefunc(Thingy func, char **args, int set_bindk) opts[XTRACE] = oxt; sfcontext = osc; endparamscope(); - if (errflag == ERRFLAG_ERROR && !(ret = execimmortal(func, args))) + if (errflag == ERRFLAG_ERROR) { + int saverr = errflag; errflag &= ~ERRFLAG_ERROR; + if ((ret = execimmortal(func, args)) != 0) + errflag |= saverr; + } lastcmd = w->flags & ~(WIDGET_INUSE|WIDGET_FREE); if (inuse) { w->flags &= WIDGET_INUSE|WIDGET_FREE; -- cgit v1.2.3