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 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'Src/Zle/zle_keymap.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) { -- cgit v1.2.3 From 597fa5ee5d1bda8f91f6f0e4716c5fccc9927cf6 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Tue, 10 May 2016 13:20:53 -0700 Subject: 38463: use immortal widgets in .safe keymap --- ChangeLog | 4 ++++ Src/Zle/zle_keymap.c | 16 ++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'Src/Zle/zle_keymap.c') diff --git a/ChangeLog b/ChangeLog index 5caeeccef..4c10e772a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2016-05-10 Barton E. Schaefer + + * 38463: Src/Zle/zle_keymap.c: use immortal widgets in .safe keymap + 2016-05-10 Daniel Shahaf * unposted: Functions/Math/.distfiles, Functions/Math/zmathfunc: diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index 13fd13844..f547dbf17 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -1322,15 +1322,15 @@ default_bindings(void) amap->first[i] = refthingy(t_undefinedkey); /* safe fallback keymap: - * 0-255 self-insert, except: * - * '\n' accept-line * - * '\r' accept-line */ + * 0-255 .self-insert, except: * + * '\n' .accept-line * + * '\r' .accept-line */ for (i = 0; i < 256; i++) - smap->first[i] = refthingy(t_selfinsert); - unrefthingy(t_selfinsert); - unrefthingy(t_selfinsert); - smap->first['\n'] = refthingy(t_acceptline); - smap->first['\r'] = refthingy(t_acceptline); + smap->first[i] = refthingy(t_Dselfinsert); + unrefthingy(t_Dselfinsert); + unrefthingy(t_Dselfinsert); + smap->first['\n'] = refthingy(t_Dacceptline); + smap->first['\r'] = refthingy(t_Dacceptline); /* vt100 arrow keys are bound by default, for historical reasons. * * Both standard and keypad modes are supported. */ -- cgit v1.2.3 From a73ae70e8217d7163aecdbdad4d8af08eced8a55 Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Wed, 29 Jun 2016 17:05:06 +0200 Subject: 38770: vi upper/lowercase widgets and shell widget example that reads a vi movement --- ChangeLog | 4 ++++ Doc/Zsh/contrib.yo | 11 +++++++++++ Doc/Zsh/zle.yo | 14 ++++++++++++++ Functions/Zle/vi-pipe | 31 +++++++++++++++++++++++++++++++ Src/Zle/iwidgets.list | 2 ++ Src/Zle/zle_keymap.c | 5 ++++- Src/Zle/zle_vi.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 Functions/Zle/vi-pipe (limited to 'Src/Zle/zle_keymap.c') diff --git a/ChangeLog b/ChangeLog index 4f0a49397..831ea4e69 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2016-06-29 Oliver Kiddle + * 38770: Src/Zle/zle_keymap.c, Src/Zle/zle_vi.c, Doc/Zsh/zle.yo, + Doc/Zsh/contrib.yo, Functions/Zle/vi-pipe: vi upper/lowercase + widgets and shell widget example that reads a vi movement + * 38752: Src/builtin.c: add comments to explain use of stdout instead of stderr for the which builtin diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index 53ae96dad..f1208e843 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -2968,6 +2968,17 @@ and aliases `tt(globurl)' to `tt(noglob urlglobber)'. This function takes a local URL apart, attempts to pattern-match the local file portion of the URL path, and then puts the results back into URL format again. ) +tindex(vi-pipe) +item(tt(vi-pipe))( +This function reads a movement command from the keyboard and then +prompts for an external command. The part of the buffer covered by +the movement is piped to the external command and then replaced by +the command's output. If the movement command is bound to vi-pipe, +the current line is used. + +The function serves as an example for reading a vi movement command +from within a user-defined widget. +) tindex(which-command) item(tt(which-command))( This function is a drop-in replacement for the builtin widget diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index 80d3f39d8..1bae0ccf7 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -1781,6 +1781,13 @@ tindex(down-case-word) item(tt(down-case-word) (tt(ESC-L ESC-l)) (unbound) (unbound))( Convert the current word to all lowercase and move past it. ) +tindex(vi-down-case) +item(tt(vi-down-case)) ((unbound) (tt(gu)) (unbound))( +Read a movement command from the keyboard, and convert all characters +from the cursor position to the endpoint of the movement to lowercase. +If the movement command is tt(vi-down-case), swap the case of all +characters on the current line. +) tindex(kill-word) item(tt(kill-word) (tt(ESC-D ESC-d)) (unbound) (unbound))( Kill the current word. @@ -1946,6 +1953,13 @@ tindex(vi-unindent) item(tt(vi-unindent) (unbound) (tt(<)) (unbound))( Unindent a number of lines. ) +tindex(vi-up-case) +item(tt(vi-up-case)) ((unbound) (tt(gU)) (unbound))( +Read a movement command from the keyboard, and convert all characters +from the cursor position to the endpoint of the movement to lowercase. +If the movement command is tt(vi-up-case), swap the case of all +characters on the current line. +) tindex(up-case-word) item(tt(up-case-word) (tt(ESC-U ESC-u)) (unbound) (unbound))( Convert the current word to all caps and move past it. diff --git a/Functions/Zle/vi-pipe b/Functions/Zle/vi-pipe new file mode 100644 index 000000000..2d2e29587 --- /dev/null +++ b/Functions/Zle/vi-pipe @@ -0,0 +1,31 @@ +# Example of a widget that takes a vi motion + +# Filter part of buffer corresponding to a vi motion through an external +# program. + +# To enable with vi compatible bindings use: +# autoload -Uz vi-pipe +# bindkey -a '!' vi-pipe + +autoload -Uz read-from-minibuffer +local _save_cut="$CUTBUFFER" REPLY + +# Use the standard vi-delete to accept a vi motion. +zle .vi-delete || return +read-from-minibuffer "!" +local _save_cur=$CURSOR + +# cut buffer contains the deleted text and can be modified +CUTBUFFER="$(eval $REPLY <<<$CUTBUFFER)" + +# put the modified text back in position. +if [[ CURSOR -eq 0 || $BUFFER[CURSOR] = $'\n' ]]; then + # at the beginning of a line, vi-delete won't have moved the cursor + # back to a previous line + zle .vi-put-before -n 1 +else + zle .vi-put-after -n 1 +fi + +# restore cut buffer and cursor to the start of the range +CUTBUFFER="$_save_cut" CURSOR="$_save_cur" diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list index 2b2654c5d..58310cd74 100644 --- a/Src/Zle/iwidgets.list +++ b/Src/Zle/iwidgets.list @@ -143,6 +143,7 @@ "vi-delete", videlete, ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_VIOPER "vi-delete-char", videletechar, ZLE_KEEPSUFFIX "vi-digit-or-beginning-of-line", vidigitorbeginningofline, 0 +"vi-down-case", vidowncase, ZLE_LASTCOL | ZLE_VIOPER "vi-down-line-or-history", vidownlineorhistory, ZLE_LINEMOVE "vi-end-of-line", viendofline, ZLE_LASTCOL "vi-fetch-history", vifetchhistory, ZLE_LINEMOVE @@ -188,6 +189,7 @@ "vi-swap-case", viswapcase, ZLE_LASTCOL "vi-undo-change", viundochange, ZLE_KEEPSUFFIX "vi-unindent", viunindent, ZLE_LASTCOL | ZLE_VIOPER +"vi-up-case", viupcase, ZLE_LASTCOL | ZLE_VIOPER "vi-up-line-or-history", viuplineorhistory, ZLE_LINEMOVE "vi-yank", viyank, ZLE_LASTCOL | ZLE_VIOPER "vi-yank-eol", viyankeol, 0 diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index f547dbf17..3db4207d9 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -1374,8 +1374,11 @@ default_bindings(void) bindkey(amap, "ge", refthingy(t_vibackwardwordend), NULL); bindkey(amap, "gE", refthingy(t_vibackwardblankwordend), NULL); bindkey(amap, "gg", refthingy(t_beginningofbufferorhistory), NULL); - bindkey(amap, "g~", refthingy(t_vioperswapcase), NULL); + bindkey(amap, "gu", refthingy(t_vidowncase), NULL); + bindkey(amap, "gU", refthingy(t_viupcase), NULL); bindkey(amap, "g~~", NULL, "g~g~"); + bindkey(amap, "guu", NULL, "gugu"); + bindkey(amap, "gUU", NULL, "gUgU"); /* emacs mode: arrow keys */ add_cursor_key(emap, TCUPCURSOR, t_uplineorhistory, 'A'); diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c index 953af2401..baa2064e9 100644 --- a/Src/Zle/zle_vi.c +++ b/Src/Zle/zle_vi.c @@ -729,6 +729,52 @@ vioperswapcase(UNUSED(char **args)) return ret; } +/**/ +int +viupcase(UNUSED(char **args)) +{ + int oldcs, c2, ret = 1; + + /* get the range */ + startvichange(1); + if ((c2 = getvirange(0)) != -1) { + oldcs = zlecs; + /* covert the case of all letters within range */ + while (zlecs < c2) { + zleline[zlecs] = ZC_toupper(zleline[zlecs]); + INCCS(); + } + /* go back to the first line of the range */ + zlecs = oldcs; + ret = 0; + } + vichgflag = 0; + return ret; +} + +/**/ +int +vidowncase(UNUSED(char **args)) +{ + int oldcs, c2, ret = 1; + + /* get the range */ + startvichange(1); + if ((c2 = getvirange(0)) != -1) { + oldcs = zlecs; + /* convert the case of all letters within range */ + while (zlecs < c2) { + zleline[zlecs] = ZC_tolower(zleline[zlecs]); + INCCS(); + } + /* go back to the first line of the range */ + zlecs = oldcs; + ret = 0; + } + vichgflag = 0; + return ret; +} + /**/ int virepeatchange(UNUSED(char **args)) -- cgit v1.2.3 From 696444714e9670f1f725381abde2cd8cb20d59dd Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Wed, 2 Nov 2016 21:33:34 -0700 Subject: 39813: fix keybuflen after ungetting extra keys from the end of keybuf in getkeymapcmd(). --- ChangeLog | 3 +++ Src/Zle/zle_keymap.c | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'Src/Zle/zle_keymap.c') diff --git a/ChangeLog b/ChangeLog index 63c80e04d..6deb834d3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,9 @@ 2016-11-02 Barton E. Schaefer + * 39813: Src/Zle/zle_keymap.c: fix keybuflen after ungetting + extra keys from the end of keybuf in getkeymapcmd(). + * 39811: Src/Zle/zle_vi.c: vi-repeat-change must not be the "motion" of vi-change, lest it infinitely repeat itself. diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index 3db4207d9..34c9c686e 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -135,7 +135,10 @@ mod_export HashTable keymapnamtab; /**/ char *keybuf; -static int keybuflen, keybufsz = 20; +/**/ +int keybuflen; + +static int keybufsz = 20; /* last command executed with execute-named-command */ @@ -1622,7 +1625,7 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp) ungetbytes(keybuf+lastlen, keybuflen); if(vichgflag) vichgbufptr -= keybuflen; - keybuf[lastlen] = 0; + keybuf[keybuflen = lastlen] = 0; } *funcp = func; *strp = str; -- cgit v1.2.3 From 533d839384492fcdf851a94f597c989491d9b361 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 3 Nov 2016 17:03:37 +0000 Subject: unposted: comment explaining key buffer handling. Describe putting back the tail end of the key buffer into the input. --- ChangeLog | 5 +++++ Src/Zle/zle_keymap.c | 7 +++++++ 2 files changed, 12 insertions(+) (limited to 'Src/Zle/zle_keymap.c') diff --git a/ChangeLog b/ChangeLog index ed07399a6..cc78b8595 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2016-11-03 Peter Stephenson + + * unposted: Src/Zle/zle_keymap.c: comment explaining putting + back tail end of key buffer into input. + 2016-11-03 Daniel Shahaf * 39806: Src/Zle/zle_vi.c: internal: Document zle's vichgbuf. diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index 34c9c686e..053b097bb 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -1621,6 +1621,13 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp) else lastchar = lastc; if(lastlen != keybuflen) { + /* + * We want to keep only the first lastlen bytes of the key + * buffer in the key buffer that were marked as used by the key + * binding above, and make the rest available for input again. + * That rest (but not what we are keeping) needs to be + * unmetafied. + */ unmetafy(keybuf + lastlen, &keybuflen); ungetbytes(keybuf+lastlen, keybuflen); if(vichgflag) -- cgit v1.2.3 From 0a6098a1d4debda1d57f4a7cd42bb5c49d65cddc Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Thu, 17 Nov 2016 12:28:41 +0100 Subject: 39962: bind vi case conversion widgets u/U in visual mode and g~ from normal mode --- ChangeLog | 3 +++ Src/Zle/zle_keymap.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'Src/Zle/zle_keymap.c') diff --git a/ChangeLog b/ChangeLog index ce2e13871..f51d1a0de 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2016-11-17 Oliver Kiddle + * 39962: Src/Zle/zle_keymap.c: bind vi case conversion widgets + u/U in visual mode and g~ from normal mode + * 39959: Src/Zle/zle_vi.c, Test/X02zlevi.ztst: when repeating vi changes advance through the numbered killring registers. Also fix numeric arguments with vi-repeat-change. diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index 053b097bb..24e8d1964 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -1369,6 +1369,8 @@ default_bindings(void) bindkey(vismap, "\33", refthingy(t_deactivateregion), NULL); bindkey(vismap, "o", refthingy(t_exchangepointandmark), NULL); bindkey(vismap, "p", refthingy(t_putreplaceselection), NULL); + bindkey(vismap, "u", refthingy(t_vidowncase), NULL); + bindkey(vismap, "U", refthingy(t_viupcase), NULL); bindkey(vismap, "x", refthingy(t_videlete), NULL); bindkey(vismap, "~", refthingy(t_vioperswapcase), NULL); @@ -1379,6 +1381,7 @@ default_bindings(void) bindkey(amap, "gg", refthingy(t_beginningofbufferorhistory), NULL); bindkey(amap, "gu", refthingy(t_vidowncase), NULL); bindkey(amap, "gU", refthingy(t_viupcase), NULL); + bindkey(amap, "g~", refthingy(t_vioperswapcase), NULL); bindkey(amap, "g~~", NULL, "g~g~"); bindkey(amap, "guu", NULL, "gugu"); bindkey(amap, "gUU", NULL, "gUgU"); -- 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_keymap.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