From 4b66ec003ff0631e39240576920dda971d555f6d Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Tue, 4 Nov 2014 14:08:20 +0100 Subject: 33596: make local keymap keybinding hide global keymap binding that is a prefix of the local binding --- Src/Zle/zle_keymap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Src/Zle/zle_keymap.c') diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index e21e769bd..6a7107609 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -1435,7 +1435,7 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp) loc = ((f = keybind(localkeymap, keybuf, &s)) != t_undefinedkey); ispfx = keyisprefix(localkeymap, keybuf); } - if (!loc) + if (!loc && !ispfx) f = keybind(km, keybuf, &s); ispfx |= keyisprefix(km, keybuf); -- cgit v1.2.3 From d29e02c1a30c136cbd8847a4dc4628da90566716 Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Mon, 17 Nov 2014 23:00:49 +0100 Subject: 33704: keybindings, documentation, tests and minor fixes for vim style visual selection changes --- ChangeLog | 5 +++ Doc/Zsh/zle.yo | 38 +++++++++++++++-- Src/Zle/zle_bindings.c | 4 +- Src/Zle/zle_keymap.c | 22 +++++++++- Src/Zle/zle_refresh.c | 5 +-- Src/Zle/zle_vi.c | 8 +--- Test/X02zlevi.ztst | 109 +++++++++++++++++++++++++++++++++++++++++++++++++ Test/comptest | 2 +- 8 files changed, 176 insertions(+), 17 deletions(-) (limited to 'Src/Zle/zle_keymap.c') diff --git a/ChangeLog b/ChangeLog index e181b3852..6fd41e4a9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2014-11-17 Oliver Kiddle + * 33704: Doc/Zsh/zle.yo, Src/Zle/zle_bindings.c, + Src/Zle/zle_keymap.c, Src/Zle/zle_refresh.c, Src/Zle/zle_vi.c, + Test/X02zlevi.ztst, Test/comptest: key bindings, documentation, + tests and minor fixes for vim style visual selection changes + * 33636: Src/Zle/iwidgets.list, Src/Zle/zle_misc.c, Src/Zle/zle_move.c, Src/Zle/zle_refresh.c, Src/Zle/zle_vi.c: add support for a linewise visual selection mode diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index 998bf4a10..aa7ff4b57 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -60,12 +60,14 @@ or more names. If all of a keymap's names are deleted, it disappears. findex(bindkey, use of) tt(bindkey) can be used to manipulate keymap names. -Initially, there are six keymaps: +Initially, there are eight keymaps: startsitem() sitem(tt(emacs))(EMACS emulation) sitem(tt(viins))(vi emulation - insert mode) sitem(tt(vicmd))(vi emulation - command mode) +sitem(tt(viopp))(vi emulation - operator pending) +sitem(tt(visual))(vi emulation - selection active) sitem(tt(isearch))(incremental search mode) sitem(tt(command))(read a command name) sitem(tt(.safe))(fallback keymap) @@ -122,6 +124,21 @@ in user-defined widgets with the tt(read-command) widget, described ifzman(below)\ ifnzman(in noderef(Miscellaneous) below)\ . +subsect(Local Keymaps) +cindex(local keymaps) +While for normal editing a single keymap is used exclusively, in many +modes a local keymap allows for some keys to be customised. For example, +in an incremental search mode, a binding in the tt(isearch) keymap will +override a binding in the tt(main) keymap but all keys that are not +overriden can still be used. + +If a key sequence is defined in a local keymap, it will hide a key +sequence in the global keymap that is a prefix of that sequence. An +example of this occurs with the binding of tt(iw) in tt(viopp) as this +hides the binding of tt(i) in tt(vicmd). However, a longer sequence in +the global keymap that shares the same prefix can still apply so for +example the binding of tt(^Xa) in the global keymap will be unaffected +by the binding of tt(^Xb) in the local keymap. texinode(Zle Builtins)(Zle Widgets)(Keymaps)(Zsh Line Editor) sect(Zle Builtins) @@ -817,7 +834,10 @@ cursor remains between the new tt($LBUFFER) and the old tt($RBUFFER). ) vindex(MARK) item(tt(MARK) (integer))( -Like tt(CURSOR), but for the mark. +Like tt(CURSOR), but for the mark. With vi-mode operators that wait for +a movement command to select a region of text, setting tt(MARK) allows +the selection to extend in both directions from the the initial cursor +position. ) vindex(NUMERIC) item(tt(NUMERIC) (integer))( @@ -863,7 +883,9 @@ cursor remains between the old tt($LBUFFER) and the new tt($RBUFFER). vindex(REGION_ACTIVE) item(tt(REGION_ACTIVE) (integer))( Indicates if the region is currently active. It can be assigned 0 or 1 -to deactivate and activate the region respectively; +to deactivate and activate the region respectively. A value of 2 +activates the region in line-wise mode with the highlighted text +extending for whole lines only; ifzman(see em(Character Highlighting) below)\ ifnzman(noderef(Character Highlighting)). ) @@ -2275,6 +2297,16 @@ item(tt(vi-undo-change) (unbound) (u) (unbound))( Undo the last text modification. If repeated, redo the modification. ) +tindex(visual-mode) +item(tt(visual-mode) (unbound) (v) (unbound))( +Toggle vim-style visual selection mode. If line-wise visual mode is +currently enabled then it is changed to being character-wise. +) +tindex(visual-line-mode) +item(tt(visual-line-mode) (unbound) (V) (unbound))( +Toggle vim-style line-wise visual selection mode. If character-wise +visual mode is currently enabled then it is changed to being line-wise. +) tindex(what-cursor-position) item(tt(what-cursor-position) (^X=) (unbound) (unbound))( Print the character under the cursor, its code as an octal, decimal and diff --git a/Src/Zle/zle_bindings.c b/Src/Zle/zle_bindings.c index 682691347..50a29551d 100644 --- a/Src/Zle/zle_bindings.c +++ b/Src/Zle/zle_bindings.c @@ -376,7 +376,7 @@ int vicmdbind[128] = { /* S */ z_vichangewholeline, /* T */ z_vifindprevcharskip, /* U */ z_undefinedkey, - /* V */ z_undefinedkey, + /* V */ z_visuallinemode, /* W */ z_viforwardblankword, /* X */ z_vibackwarddeletechar, /* Y */ z_viyankwholeline, @@ -408,7 +408,7 @@ int vicmdbind[128] = { /* s */ z_visubstitute, /* t */ z_vifindnextcharskip, /* u */ z_viundochange, - /* v */ z_undefinedkey, + /* v */ z_visualmode, /* w */ z_viforwardword, /* x */ z_videletechar, /* y */ z_viyank, diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index 6a7107609..216e302d0 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -1277,8 +1277,10 @@ default_bindings(void) Keymap vmap = newkeymap(NULL, "viins"); Keymap emap = newkeymap(NULL, "emacs"); Keymap amap = newkeymap(NULL, "vicmd"); + Keymap oppmap = newkeymap(NULL, "viopp"); + Keymap vismap = newkeymap(NULL, "visual"); Keymap smap = newkeymap(NULL, ".safe"); - Keymap vimaps[2], kptr; + Keymap vimaps[2], vilmaps[2], kptr; char buf[3], *ed; int i; @@ -1332,6 +1334,22 @@ default_bindings(void) add_cursor_key(kptr, TCLEFTCURSOR, t_vibackwardchar, 'D'); add_cursor_key(kptr, TCRIGHTCURSOR, t_viforwardchar, 'C'); } + vilmaps[0] = oppmap; + vilmaps[1] = vismap; + for (i = 0; i < 2; i++) { + /* vi visual selection and operator pending local maps */ + kptr = vilmaps[i]; + add_cursor_key(kptr, TCUPCURSOR, t_upline, 'A'); + add_cursor_key(kptr, TCDOWNCURSOR, t_downline, 'B'); + bindkey(kptr, "k", refthingy(t_upline), NULL); + bindkey(kptr, "j", refthingy(t_downline), NULL); + } + /* escape in operator pending cancels the operation */ + bindkey(oppmap, "\33", refthingy(t_vicmdmode), NULL); + bindkey(vismap, "o", refthingy(t_exchangepointandmark), NULL); + bindkey(vismap, "p", refthingy(t_putreplaceselection), NULL); + bindkey(vismap, "x", refthingy(t_videlete), NULL); + bindkey(vismap, "~", refthingy(t_vioperswapcase), NULL); /* emacs mode: arrow keys */ add_cursor_key(emap, TCUPCURSOR, t_uplineorhistory, 'A'); @@ -1373,6 +1391,8 @@ default_bindings(void) linkkeymap(vmap, "viins", 0); linkkeymap(emap, "emacs", 0); linkkeymap(amap, "vicmd", 0); + linkkeymap(oppmap, "viopp", 0); + linkkeymap(vismap, "visual", 0); linkkeymap(smap, ".safe", 1); if (((ed = zgetenv("VISUAL")) && strstr(ed, "vi")) || ((ed = zgetenv("EDITOR")) && strstr(ed, "vi"))) diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index f0351ad15..467629d25 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -1037,8 +1037,6 @@ zrefresh(void) region_highlights[0].start = mark; region_highlights[0].end = zlecs; } - if (invicmdmode()) - INCPOS(region_highlights[0].end); if (region_active == 2) { int origcs = zlecs; zlecs = region_highlights[0].end; @@ -1046,7 +1044,8 @@ zrefresh(void) zlecs = region_highlights[0].start; region_highlights[0].start = findbol(); zlecs = origcs; - } + } else if (invicmdmode()) + INCPOS(region_highlights[0].end); } else { region_highlights[0].start = region_highlights[0].end = -1; } diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c index 3a4304ced..84cba7759 100644 --- a/Src/Zle/zle_vi.c +++ b/Src/Zle/zle_vi.c @@ -258,7 +258,7 @@ getvirange(int wf) pos = tmp; } - if (visual && invicmdmode()) + if (visual == 1 && invicmdmode()) INCPOS(pos); /* Was it a line-oriented move? If so, the command will have set * @@ -389,9 +389,6 @@ videletechar(char **args) startvichange(-1); - if (region_active) - return killregion(args); - /* handle negative argument */ if (n < 0) { int ret; @@ -804,9 +801,6 @@ vibackwarddeletechar(char **args) if (invicmdmode()) startvichange(-1); - if (region_active) - return killregion(args); - /* handle negative argument */ if (n < 0) { int ret; diff --git a/Test/X02zlevi.ztst b/Test/X02zlevi.ztst index 297fb9aee..94afb60eb 100644 --- a/Test/X02zlevi.ztst +++ b/Test/X02zlevi.ztst @@ -273,6 +273,115 @@ >BUFFER: one wo >CURSOR: 2 + zletest $'one two\evbcx' +0:change selection +>BUFFER: one x +>CURSOR: 5 + + zletest $'four\eOthree\eOtwo\eOone\evjjhCnew' +0:change character wise selection with C acts linewise +>BUFFER: new +>four +>CURSOR: 3 + + zletest $'x testing\ehvbx' +0:x kills selections +>BUFFER: x g +>CURSOR: 2 + + zletest $'one two\eyb0vep' +0:put over selection at start of buffer +>BUFFER: tw two +>CURSOR: 1 + + zletest $'hello\C-wbye\evhp' +0:put over selection at end of buffer +>BUFFER: bhello +>CURSOR: 5 + + zletest $'one\eotwo\eyykVp' +0:yank linewise and put over linewise selection at start of buffer +>BUFFER: two +>two +>CURSOR: 0 + + zletest $'one\eotwo\eothree\eyykVp' +0:yank linewise and put over linewise selection in middle of buffer +>BUFFER: one +>three +>three +>CURSOR: 4 + + zletest $'two\eOone\eyyjVp' +0:yank linewise and put over linewise selection at end of buffer +>BUFFER: one +>one +>CURSOR: 4 + + zletest $'one\eyhVp' +0:yank character-wise and put over linewise selection +>BUFFER: n +>CURSOR: 0 + +# vim puts a blank line above in this test + zletest $'one\eotwo\eyy0kvlp' +0:yank linewise and put over character-wise selection at start of buffer +>BUFFER: two +>e +>two +>CURSOR: 0 + + zletest $'one\eyyhvp' +0:yank linewise and put over character-wise selection in middle of buffer +>BUFFER: o +>one +>e +>CURSOR: 2 + +# vim behaviour on this one really looks like a bug + zletest $'two\eOone\eyyjvhp' +0:yank linewise and put over character-wise selection at end of buffer +>BUFFER: one +>t +>one +>CURSOR: 6 + + zletest $'abc123456789\exxxxxxxxxhv"9p0P' +0:paste last (9th) register over a selection +>BUFFER: ba9c +>CURSOR: 0 + + zletest $'one\eo\eo\eotwo\ekkVdvd' +0:delete blank line using selection +>BUFFER: one +>two +>CURSOR: 4 + + zletest $'One Two Three\e2bvw~' +0:toggle case of selection +>BUFFER: One tWO three +>CURSOR: 4 + + zletest $' ----word ---- word word---- ----\e42|daw30|daw22|daw14|daw2|daw' +0:delete all word on blanks +>BUFFER: word +>CURSOR: 0 + + zletest $' word----word word----word word \e38|daw30|daw22|daw14|daw6|daw' +0:delete all word on alphanumerics +>BUFFER: -------- +>CURSOR: 4 + + zletest $' ----word---- ----word---- ---- \e38|daw30|daw22|daw14|daw6|daw' +0:delete all word on other characters +>BUFFER: wordword +>CURSOR: 4 + + zletest $'- word word\e4|2daw' +0:delete all word with numeric argument +>BUFFER: - +>CURSOR: 0 + %clean zmodload -ui zsh/zpty diff --git a/Test/comptest b/Test/comptest index 654c0f168..c67237a9a 100644 --- a/Test/comptest +++ b/Test/comptest @@ -34,7 +34,7 @@ comptestinit () { "fpath=( $fpath )" \ "bindkey -$comptest_keymap" \ 'LISTMAX=10000000 -stty 38400 columns 80 rows 24 werase undef +stty 38400 columns 80 rows 24 werase undef tabs TERM=vt100 KEYTIMEOUT=1 setopt zle -- cgit v1.2.3 From 58da0f495cdf2bbef6a7043f5f06c77991c79a9e Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Fri, 21 Nov 2014 01:08:25 +0100 Subject: 33730: vim style text objects for selecting words --- ChangeLog | 8 +- Doc/Zsh/zle.yo | 46 +++++++- Src/Zle/iwidgets.list | 6 + Src/Zle/textobjects.c | 321 ++++++++++++++++++++++++++++++++++++++++++++++++++ Src/Zle/zle.mdd | 3 +- Src/Zle/zle_keymap.c | 6 + Test/X02zlevi.ztst | 39 ++++++ 7 files changed, 426 insertions(+), 3 deletions(-) create mode 100644 Src/Zle/textobjects.c (limited to 'Src/Zle/zle_keymap.c') diff --git a/ChangeLog b/ChangeLog index d88596e57..9e1b0206e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2014-11-21 Oliver Kiddle + + * 33730: Doc/Zsh/zle.yo, Src/Zle/iwidgets.list, + Src/Zle/textobjects.c, Src/Zle/zle.mdd, Src/Zle/zle_keymap.c, + Test/X02zlevi.ztst: vim style text objects for selecting words + 2014-11-21 Peter Stephenson * Sebastien Alaiwan: 33728: Completion/Unix/Command/_bzr: @@ -20,7 +26,7 @@ 2014-11-17 Oliver Kiddle * 33704: Doc/Zsh/zle.yo, Src/Zle/zle_bindings.c, - Src/Zle/zle_keX4aymap.c, Src/Zle/zle_refresh.c, Src/Zle/zle_vi.c, + Src/Zle/zle_keymap.c, Src/Zle/zle_refresh.c, Src/Zle/zle_vi.c, Test/X02zlevi.ztst, Test/comptest: key bindings, documentation, tests and minor fixes for vim style visual selection changes diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index aa7ff4b57..f9dcd8016 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -1975,7 +1975,7 @@ When a previous completion displayed a list below the prompt, this widget can be used to move the prompt below the list. ) enditem() -texinode(Miscellaneous)()(Completion)(Zle Widgets) +texinode(Miscellaneous)(Text Objects)(Completion)(Zle Widgets) subsect(Miscellaneous) startitem() tindex(accept-and-hold) @@ -2333,6 +2333,50 @@ If the last command executed was a digit as part of an argument, continue the argument. Otherwise, execute vi-beginning-of-line. ) enditem() +texinode(Text Objects)()(Miscellaneous)(Zle Widgets) +subsect(Text Objects) +cindex(text objects) +Text objects are commands that can be used to select a block of text +according to some criteria. They are a feature of the vim text editor +and so are primarily intended for use with vi operators or from visual +selection mode. However, they can also be used from vi-insert or emacs +mode. Key bindings listed below apply to the tt(viopp) and tt(visual) +keymaps. + +startitem() +tindex(select-a-blank-word) +item(tt(select-a-blank-word) (aW))( +Select a word including adjacent blanks, where a word is defined as a +series of non-blank characters. With a numeric argument, multiple words +will be selected. +) +tindex(select-a-shell-word) +item(tt(select-a-shell-word) (aa))( +Select the current command argument applying the normal rules for +quoting. +) +tindex(select-a-word) +item(tt(select-a-word) (aw))( +Select a word including adjacent blanks, using the normal vi-style word +definition. With a numeric argument, multiple words will be selected. +) +tindex(select-in-blank-word) +item(tt(select-in-blank-word) (iW))( +Select a word, where a word is defined as a series of non-blank +characters. With a numeric argument, multiple words will be selected. +) +tindex(select-in-shell-word) +item(tt(select-in-shell-word) (ia))( +Select the current command argument applying the normal rules for +quoting. If the argument begins and ends with matching quote characters, +these are not included in the selection. +) +tindex(select-in-word) +item(tt(select-in-word) (iw))( +Select a word, using the normal vi-style word definition. With a numeric +argument, multiple words will be selected. +) +enditem() texinode(Character Highlighting)()(Zle Widgets)(Zsh Line Editor) sect(Character Highlighting) diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list index 26182974a..1a664e5e8 100644 --- a/Src/Zle/iwidgets.list +++ b/Src/Zle/iwidgets.list @@ -100,6 +100,12 @@ "reset-prompt", resetprompt, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "reverse-menu-complete", reversemenucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP "run-help", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL +"select-a-word", selectword, ZLE_KEEPSUFFIX +"select-in-word", selectword, ZLE_KEEPSUFFIX +"select-a-blank-word", selectword, ZLE_KEEPSUFFIX +"select-in-blank-word", selectword, ZLE_KEEPSUFFIX +"select-a-shell-word", selectargument, ZLE_KEEPSUFFIX +"select-in-shell-word", selectargument, ZLE_KEEPSUFFIX "self-insert", selfinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX "self-insert-unmeta", selfinsertunmeta, ZLE_MENUCMP | ZLE_KEEPSUFFIX "send-break", sendbreak, 0 diff --git a/Src/Zle/textobjects.c b/Src/Zle/textobjects.c new file mode 100644 index 000000000..7f049c5dd --- /dev/null +++ b/Src/Zle/textobjects.c @@ -0,0 +1,321 @@ +/* + * textobjects.c - ZLE module implementing Vim style text objects + * + * This file is part of zsh, the Z shell. + * + * Copyright (c) 2014 Oliver Kiddle + * All rights reserved. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and to distribute modified versions of this software for any + * purpose, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * In no event shall Oliver Kiddle or the Zsh Development Group be liable + * to any party for direct, indirect, special, incidental, or consequential + * damages arising out of the use of this software and its documentation, + * even if Oliver Kiddle and the Zsh Development Group have been advised of + * the possibility of such damage. + * + * Oliver Kiddle and the Zsh Development Group specifically disclaim any + * warranties, including, but not limited to, the implied warranties of + * merchantability and fitness for a particular purpose. The software + * provided hereunder is on an "as is" basis, and Oliver Kiddle and the + * Zsh Development Group have no obligation to provide maintenance, + * support, updates, enhancements, or modifications. + * + */ + +#include "zle.mdh" +#include "textobjects.pro" + +/* class of character: 0 is whitespace, 1 is word character, 2 is other */ +static int +wordclass(ZLE_CHAR_T x) +{ + return (ZC_iblank(x) ? 0 : ((ZC_ialnum(x) || (ZWC('_') == x)) ? 1 : 2)); +} + +static int +blankwordclass(ZLE_CHAR_T x) +{ + return (ZC_iblank(x) ? 0 : 1); +} + +/**/ +int +selectword(UNUSED(char **args)) +{ + int n = zmult; + int all = (bindk == t_selectaword || bindk == t_selectablankword); + int (*viclass)(ZLE_CHAR_T) = (bindk == t_selectaword || + bindk == t_selectinword) ? wordclass : blankwordclass; + int sclass = viclass(zleline[zlecs]); + int doblanks = all && sclass; + + if (!invicmdmode()) { + region_active = 1; + mark = zlecs; + } + if (!region_active || zlecs == mark) { + /* search back to first character of same class as the start position + * also stop at the beginning of the line */ + mark = zlecs; + while (mark) { + int pos = mark; + DECPOS(pos); + if (zleline[pos] == ZWC('\n') || viclass(zleline[pos]) != sclass) + break; + mark = pos; + } + /* similarly scan forward over characters of the same class */ + while (zlecs < zlell) { + INCCS(); + int pos = zlecs; + /* single newlines within blanks are included */ + if (all && !sclass && pos < zlell && zleline[pos] == ZWC('\n')) + INCPOS(pos); + + if (zleline[pos] == ZWC('\n') || viclass(zleline[pos]) != sclass) + break; + } + + if (all) { + int nclass = viclass(zleline[zlecs]); + /* if either start or new position is blank advance over + * a new block of characters of a common type */ + if (!nclass || !sclass) { + while (zlecs < zlell) { + INCCS(); + if (zleline[zlecs] == ZWC('\n') || + viclass(zleline[zlecs]) != nclass) + break; + } + if (n < 2) + doblanks = 0; + } + } + } else { + /* For visual mode, advance one char so repeated + * invocations select subsequent words */ + if (zlecs > mark) { + if (zlecs < zlell) + INCCS(); + } else if (zlecs) + DECCS(); + if (zlecs < mark) { + /* visual mode with the cursor before the mark: move cursor back */ + while (n-- > 0) { + int pos = zlecs; + /* first over blanks */ + if (all && (!viclass(zleline[pos]) || + zleline[pos] == ZWC('\n'))) { + all = 0; + while (pos) { + DECPOS(pos); + if (zleline[pos] == ZWC('\n')) + break; + zlecs = pos; + if (viclass(zleline[pos])) + break; + } + } else if (zlecs && zleline[zlecs] == ZWC('\n')) { + /* for in widgets pass over one newline */ + DECPOS(pos); + if (zleline[pos] != ZWC('\n')) + zlecs = pos; + } + pos = zlecs; + sclass = viclass(zleline[zlecs]); + /* now retreat over non-blanks */ + while (zleline[pos] != ZWC('\n') && + viclass(zleline[pos]) == sclass) { + zlecs = pos; + if (!pos) { + zlecs = 0; + break; + } + DECPOS(pos); + } + /* blanks again but only if there were none first time */ + if (all && zlecs) { + pos = zlecs; + DECPOS(pos); + if (!viclass(zleline[pos])) { + while (pos) { + DECPOS(pos); + if (zleline[pos] == ZWC('\n') || + viclass(zleline[pos])) + break; + zlecs = pos; + } + } + } + } + return 0; + } + n++; + doblanks = 0; + } + region_active = !!region_active; /* force to character wise */ + + /* for each digit argument, advance over further block of one class */ + while (--n > 0) { + if (zlecs < zlell && zleline[zlecs] == ZWC('\n')) + INCCS(); + sclass = viclass(zleline[zlecs]); + while (zlecs < zlell) { + INCCS(); + if (zleline[zlecs] == ZWC('\n') || + viclass(zleline[zlecs]) != sclass) + break; + } + /* for 'a' widgets, advance extra block if either consists of blanks */ + if (all) { + if (zlecs < zlell && zleline[zlecs] == ZWC('\n')) + INCCS(); + if (!sclass || !viclass(zleline[zlecs]) ) { + sclass = viclass(zleline[zlecs]); + if (n == 1 && !sclass) + doblanks = 0; + while (zlecs < zlell) { + INCCS(); + if (zleline[zlecs] == ZWC('\n') || + viclass(zleline[zlecs]) != sclass) + break; + } + } + } + } + + /* if we didn't remove blanks at either end we remove some at the start */ + if (doblanks) { + int pos = mark; + while (pos) { + DECPOS(pos); + /* don't remove blanks at the start of the line, i.e indentation */ + if (zleline[pos] == ZWC('\n')) + break; + if (!ZC_iblank(zleline[pos])) { + INCPOS(pos); + mark = pos; + break; + } + } + } + /* Adjustment: vi operators don't include the cursor position, in insert + * or emacs mode the region also doesn't but for vi visual mode it is + * included. */ + if (zlecs && zlecs > mark && !virangeflag) + DECCS(); + + return 0; +} + +/**/ +int +selectargument(UNUSED(char **args)) +{ + int ne = noerrs, ocs = zlemetacs; + int owb = wb, owe= we, oadx = addedx, ona = noaliases; + char *p; + int ll, cs; + char *linein; + int wend = 0, wcur = 0; + int n = zmult; + int *wstarts; + int tmpsz; + + if (n < 1 || 2*n > zlell + 1) + return 1; + + /* if used from emacs mode enable the region */ + if (!invicmdmode()) { + region_active = 1; + mark = zlecs; + } + + wstarts = (int *) zhalloc(n * sizeof(int)); + memset(wstarts, 0, n * sizeof(int)); + + addedx = 0; + noerrs = 1; + lexsave(); + lexflags = LEXFLAGS_ACTIVE; + linein = zlegetline(&ll, &cs); + zlemetall = ll; + zlemetacs = cs; + + if (!isfirstln && chline) { + p = (char *) zhalloc(hptr - chline + zlemetall + 2); + memcpy(p, chline, hptr - chline); + memcpy(p + (hptr - chline), linein, ll); + p[(hptr - chline) + ll] = '\0'; + inpush(p, 0, NULL); + zlemetacs += hptr - chline; + } else { + p = (char *) zhalloc(ll + 1); + memcpy(p, linein, ll); + p[ll] = '\0'; + inpush(p, 0, NULL); + } + if (zlemetacs) + zlemetacs--; + strinbeg(0); + noaliases = 1; + do { + wstarts[wcur++] = wend; + wcur %= n; + ctxtlex(); + if (tok == ENDINPUT || tok == LEXERR) + break; + wend = zlemetall - inbufct; + } while (tok != ENDINPUT && tok != LEXERR && wend <= zlemetacs); + noaliases = ona; + strinend(); + inpop(); + errflag = 0; + noerrs = ne; + lexrestore(); + zlemetacs = ocs; + wb = owb; + we = owe; + addedx = oadx; + + /* convert offsets for mark and zlecs back to ZLE internal format */ + linein[wend] = '\0'; /* a bit of a hack to get two offsets */ + free(stringaszleline(linein, wstarts[wcur], &zlecs, &tmpsz, &mark)); + + if (bindk == t_selectinshellword) { + ZLE_CHAR_T *match = ZWS("`\'\""); + ZLE_CHAR_T *lmatch = ZWS("\'({"), *rmatch = ZWS("\')}"); + ZLE_CHAR_T *ematch = match, *found; + int start, end = zlecs; + /* for 'in' widget, don't include initial blanks ... */ + while (mark < zlecs && ZC_iblank(zleline[mark])) + INCPOS(mark); + /* ... or a matching pair of quotes */ + start = mark; + if (zleline[start] == ZWC('$')) { + match = lmatch; + ematch = rmatch; + INCPOS(start); + } + found = ZS_strchr(match, zleline[start]); + if (found) { + DECPOS(end); + if (zleline[end] == ematch[found-match]) { + zlecs = end; + INCPOS(start); + mark = start; + } + } + } + + /* Adjustment: vi operators don't include the cursor position */ + if (!virangeflag) + DECCS(); + + return 0; +} diff --git a/Src/Zle/zle.mdd b/Src/Zle/zle.mdd index c6e4d11c2..dd69eff2c 100644 --- a/Src/Zle/zle.mdd +++ b/Src/Zle/zle.mdd @@ -7,7 +7,8 @@ autofeatures="b:bindkey b:vared b:zle" objects="zle_bindings.o zle_hist.o zle_keymap.o zle_main.o \ zle_misc.o zle_move.o zle_params.o zle_refresh.o \ -zle_thingy.o zle_tricky.o zle_utils.o zle_vi.o zle_word.o" +zle_thingy.o zle_tricky.o zle_utils.o zle_vi.o zle_word.o \ +textobjects.o" headers="zle.h zle_things.h" diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index 216e302d0..30d25ebaa 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -1343,6 +1343,12 @@ default_bindings(void) add_cursor_key(kptr, TCDOWNCURSOR, t_downline, 'B'); bindkey(kptr, "k", refthingy(t_upline), NULL); bindkey(kptr, "j", refthingy(t_downline), NULL); + bindkey(kptr, "aa", refthingy(t_selectashellword), NULL); + bindkey(kptr, "ia", refthingy(t_selectinshellword), NULL); + bindkey(kptr, "aw", refthingy(t_selectaword), NULL); + bindkey(kptr, "iw", refthingy(t_selectinword), NULL); + bindkey(kptr, "aW", refthingy(t_selectablankword), NULL); + bindkey(kptr, "iW", refthingy(t_selectinblankword), NULL); } /* escape in operator pending cancels the operation */ bindkey(oppmap, "\33", refthingy(t_vicmdmode), NULL); diff --git a/Test/X02zlevi.ztst b/Test/X02zlevi.ztst index 94afb60eb..6b7ca567e 100644 --- a/Test/X02zlevi.ztst +++ b/Test/X02zlevi.ztst @@ -380,6 +380,45 @@ zletest $'- word word\e4|2daw' 0:delete all word with numeric argument >BUFFER: - +>CURSOR: 0 + + zletest $'---- word ----word\eo \eo----\eodone\eh' \ + 'vhawmaawmbawmcawmdawmeawmfawmgv`ara`brb`crc$r$`drd`ere`frf`grg' +0:all word with existing selection and cursor before mark +>BUFFER: g---f worde ----dord +>c $ +>b--- +>aone +>CURSOR: 0 + + zletest $'---- word word----\e0lvlawmaawmbawmcawvrd`ara`brb`crc' +0:all word with existing selection and mark before cursor +>BUFFER: ---- aword bworc---d +>CURSOR: 19 + + zletest $' --ww ww---\eo\eoww\evhiwiw' m{a,b,c,d,e}iw vrE \`{a,b,c,d,e}r. +0:in word with existing selection and cursor before mark +>BUFFER: E.-.w. .w.-- +> +>ww +>CURSOR: 1 + + zletest $' --ww ww--\eO \ev0o' m{a,b,c,d,e}iw vrE \`{a,b,c,d,e}r. +0:in word with existing selection and mark before cursor +>BUFFER: . +> .-.w. .wE-- +>CURSOR: 10 + + zletest $' `one` $(echo two) " three " $\'four\'\C-v\tfive ${six:-6}\e' \ + vaaom{a,b,c,d,e,f}v \`{a,b,c,d,e,f}rX +0:all argument for different arguments +>BUFFER: X `one`X $(echo two)X" three "X$'four'XfiveX${six:-6} +>CURSOR: 0 + + zletest $'{ls `echo x` $((3+4)) "a b" $\'\\t\\n\' ${d%/}\e' \ + cia{6,5,4,3,2,1}$'\eBB' +0:in argument for different arguments +>BUFFER: 1ls `2` $(3) "4" $'5' ${6} >CURSOR: 0 %clean -- cgit v1.2.3 From d067ebcacd55472f720b2765ec686a69b25c9a90 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sun, 7 Dec 2014 16:24:19 +0000 Subject: 33876: etc.: Separate errors and keyboards interrupts Combination of 12 commits from interrupt_abort branch. Basic strategy is to introduce bits to errflag and to set and reset them separately. Remove interrupt status on return to main keymap. Turn off ERRFLAG_INT for always block. Restore bit thereafter: we probably need a new variable in order to allow user interrupts to be reset in the always block. Add TRY_BLOCK_INTERRUPT This works the same as TRY_BLOCK_ERROR, but for a SIGINT, too. Ensure propagation of SIGINT from exited job. If received by foreground job, shell uses ERRFLAG_INT, not ERRFLAG_ERROR, to set the new state. Reset errflag before precmd() Add always block in _main_completion to fix ZLS_COLORS Ensures we get the right state of $ZLS_COLORS at the end of _main_complete even if there's an interrupt. However, the "right state" is a bit messy as it depends on styles. --- ChangeLog | 20 +++++++++++-- Completion/Base/Core/_main_complete | 21 ++++++++------ Doc/Zsh/params.yo | 11 ++++++++ Src/Modules/zpty.c | 2 +- Src/Modules/zutil.c | 8 ++++-- Src/Zle/compcore.c | 2 +- Src/Zle/compctl.c | 10 +++---- Src/Zle/compresult.c | 2 +- Src/Zle/textobjects.c | 2 +- Src/Zle/zle_hist.c | 6 ++-- Src/Zle/zle_keymap.c | 10 +++++++ Src/Zle/zle_main.c | 14 ++++++---- Src/Zle/zle_misc.c | 2 +- Src/Zle/zle_tricky.c | 20 +++++++++++-- Src/Zle/zle_utils.c | 3 +- Src/builtin.c | 22 +++++++-------- Src/exec.c | 56 +++++++++++++++++++++++-------------- Src/glob.c | 12 ++++---- Src/hist.c | 10 ++++--- Src/init.c | 29 ++++++++++++++++--- Src/input.c | 3 +- Src/jobs.c | 23 +++++++++------ Src/lex.c | 5 ++-- Src/loop.c | 28 ++++++++++++++++--- Src/params.c | 13 +++++---- Src/parse.c | 31 ++++++++++---------- Src/prompt.c | 7 +++-- Src/signals.c | 28 ++++++++++++++++--- Src/subst.c | 27 ++++++++++++------ Src/utils.c | 8 +++--- Src/zsh.h | 14 ++++++++++ 31 files changed, 315 insertions(+), 134 deletions(-) (limited to 'Src/Zle/zle_keymap.c') diff --git a/ChangeLog b/ChangeLog index 94e28ccb2..e30324894 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2014-12-11 Peter Stephenson + + * 33876: etc.: Completion/Base/Core/_main_complete, + Doc/Zsh/params.yo, Src/Modules/zpty.c, Src/Modules/zutil.c, + Src/Zle/compcore.c, Src/Zle/compctl.c, Src/Zle/compresult.c, + Src/Zle/textobjects.c, Src/Zle/zle_hist.c, Src/Zle/zle_keymap.c, + Src/Zle/zle_main.c, Src/Zle/zle_misc.c, Src/Zle/zle_tricky.c, + Src/Zle/zle_utils.c, Src/builtin.c, Src/exec.c, Src/glob.c, + Src/hist.c, Src/init.c, Src/input.c, Src/jobs.c, Src/lex.c, + Src/loop.c, Src/params.c, Src/parse.c, Src/prompt.c, + Src/signals.c, Src/subst.c, Src/utils.c, Src/zsh.h: Separate + shell errors and user interrupt flags into different bits of + errflag: ERRFLAG_ERROR and ERRFLAG_INT. Various + rationalisations to make keyboard interrupts work smoothly. + Work done on interrupt_abort branch. + 2014-12-10 Mikael Magnusson * 33948: Completion/Unix/Command/_getent, @@ -612,7 +628,7 @@ * 33354: Src/jobs.c, Test/A05execution.ztst: when backgrounding a pipeline, close all pipe descriptors in the parent; add test for both this and 33345+33346 - + 2014-10-03 Bart Schaefer * 33346: Src/parse.c: another bit of the 33345 repair @@ -2083,7 +2099,7 @@ 2013-12-20 Barton E. Schaefer * 32172; Test/A05execution.ztst: regression test for 32171 - + * 32171: Src/exec.c: fix leaked pipe descriptor that could deadlock a pipeline from a complex shell construct or function into an external command diff --git a/Completion/Base/Core/_main_complete b/Completion/Base/Core/_main_complete index bc63e83fb..d6a100777 100644 --- a/Completion/Base/Core/_main_complete +++ b/Completion/Base/Core/_main_complete @@ -43,6 +43,8 @@ local -a precommands typeset -U _lastdescr _comp_ignore _comp_colors +{ + [[ -z "$curcontext" ]] && curcontext=::: zstyle -s ":completion:${curcontext}:" insert-tab tmp || tmp=yes @@ -349,17 +351,20 @@ fi ( "$_comp_force_list" = ?* && nm -ge _comp_force_list ) ]] && compstate[list]="${compstate[list]//messages} force" -if [[ "$compstate[old_list]" = keep ]]; then - if [[ $_saved_colors_set = 1 ]]; then - ZLS_COLORS="$_saved_colors" +} always { + # Stuff we always do to clean up. + if [[ "$compstate[old_list]" = keep ]]; then + if [[ $_saved_colors_set = 1 ]]; then + ZLS_COLORS="$_saved_colors" + else + unset ZLS_COLORS + fi + elif (( $#_comp_colors )); then + ZLS_COLORS="${(j.:.)_comp_colors}" else unset ZLS_COLORS fi -elif (( $#_comp_colors )); then - ZLS_COLORS="${(j.:.)_comp_colors}" -else - unset ZLS_COLORS -fi +} # Now call the post-functions. diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo index 5833d6be9..391a5fb0a 100644 --- a/Doc/Zsh/params.yo +++ b/Doc/Zsh/params.yo @@ -754,6 +754,17 @@ It may be reset, clearing the error condition. See ifzman(em(Complex Commands) in zmanref(zshmisc))\ ifnzman(noderef(Complex Commands)) ) +vindex(TRY_BLOCK_INTERRUPT) +item(tt(TRY_BLOCK_INTERRUPT) )( +This variable works in a similar way to tt(TRY_BLOCK_ERROR), but +represents the status of an interrupt from the signal SIGINT, which +typically comes from the keyboard when the user types tt(^C). If set to +0, any such interrupt will be reset; otherwise, the interrupt is +propagated after the tt(always) block. + +Note that it is possible that an interrupt arrives during the execution +of the tt(always) block; this interrupt is also propagated. +) vindex(TTY) item(tt(TTY))( The name of the tty associated with the shell, if any. diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c index 63c79a731..7b6130c6f 100644 --- a/Src/Modules/zpty.c +++ b/Src/Modules/zpty.c @@ -308,7 +308,7 @@ newptycmd(char *nam, char *pname, char **args, int echo, int nblock) prog = parse_string(zjoin(args, ' ', 1), 0); if (!prog) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; scriptname = oscriptname; ineval = oineval; return 1; diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 1cca0c4b8..c89495070 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -301,7 +301,8 @@ setstypat(Style s, char *pat, Patprog prog, char **vals, int eval) int ef = errflag; eprog = parse_string(zjoin(vals, ' ', 1), 0); - errflag = ef; + /* Keep any user interrupt error status */ + errflag = ef | (errflag & ERRFLAG_INT); if (!eprog) { @@ -394,10 +395,11 @@ evalstyle(Stypat p) unsetparam("reply"); execode(p->eval, 1, 0, "style"); if (errflag) { - errflag = ef; + /* Keep any user interrupt error status */ + errflag = ef | (errflag & ERRFLAG_INT); return NULL; } - errflag = ef; + errflag = ef | (errflag & ERRFLAG_INT); queue_signals(); if ((ret = getaparam("reply"))) diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 35d410cc6..b0c6e06f8 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -1671,7 +1671,7 @@ set_comp_sep(void) noaliases = ona; strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; noerrs = ne; lexrestore(); wb = owb; diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 0b7a32445..d15c2d1b0 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -1879,7 +1879,7 @@ ccmakehookfn(UNUSED(Hookdef dummy), struct ccmakedat *dat) if (!m || !(m = m->next)) break; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; } redup(osi, 0); dat->lst = 1; @@ -2121,7 +2121,7 @@ getreal(char *str) if (!errflag && nonempty(l) && ((char *) peekfirst(l)) && ((char *) peekfirst(l))[0]) return dupstring(peekfirst(l)); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; return dupstring(str); } @@ -2599,7 +2599,7 @@ makecomplistlist(Compctl cc, char *s, int incmd, int compadd) makecomplistflags(cc, s, incmd, compadd); /* Reset some information variables for the next try. */ - errflag = 0; + errflag &= ~ERRFLAG_ERROR; offs = oloffs; wb = owb; we = owe; @@ -2847,7 +2847,7 @@ sep_comp_string(char *ss, char *s, int noffs) noaliases = ona; strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; noerrs = ne; lexrestore(); wb = owb; @@ -3725,7 +3725,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) noaliases = ona; strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; lexrestore(); /* Fine, now do full expansion. */ prefork(foo, 0); diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c index fcceb670c..93438a053 100644 --- a/Src/Zle/compresult.c +++ b/Src/Zle/compresult.c @@ -1092,7 +1092,7 @@ do_single(Cmatch m) noerrs = 1; parsestr(p); singsub(&p); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; noerrs = ne; } } else { diff --git a/Src/Zle/textobjects.c b/Src/Zle/textobjects.c index 85d014b27..37d2c0ad9 100644 --- a/Src/Zle/textobjects.c +++ b/Src/Zle/textobjects.c @@ -275,7 +275,7 @@ selectargument(UNUSED(char **args)) noaliases = ona; strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; noerrs = ne; lexrestore(); zlemetacs = ocs; diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c index 9f65994dc..88623bb3c 100644 --- a/Src/Zle/zle_hist.c +++ b/Src/Zle/zle_hist.c @@ -853,8 +853,10 @@ pushlineoredit(char **args) free(zhline); } ret = pushline(args); - if (!isfirstln) - errflag = done = 1; + if (!isfirstln) { + errflag |= ERRFLAG_ERROR; + done = 1; + } clearlist = 1; return ret; } diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index 30d25ebaa..48f210c7e 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -504,6 +504,16 @@ mod_export void selectlocalmap(Keymap m) { localkeymap = m; + if (!m) + { + /* + * No local keymap; so we are returning to the global map. If + * the user ^Ced in the local map, they probably just want to go + * back to normal editing. So remove the interrupt error + * status. + */ + errflag &= ~ERRFLAG_INT; + } } /* Reopen the currently selected keymap, in case it got deleted. This * diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index caa052b13..a2f48e13a 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -744,7 +744,7 @@ raw_getbyte(long do_keytmout, char *cptr) } if (errflag) { /* No sensible way of handling errors here */ - errflag = 0; + errflag &= ~ERRFLAG_ERROR; /* * Paranoia: don't run the hooks again this * time. @@ -882,7 +882,7 @@ getbyte(long do_keytmout, int *timeout) die = 0; if (!errflag && !retflag && !breaks && !exit_pending) continue; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; breaks = obreaks; errno = old_errno; return lastchar = EOF; @@ -1075,7 +1075,7 @@ zlecore(void) DECCS(); handleundo(); } else { - errflag = 1; + errflag |= ERRFLAG_ERROR; break; } #ifdef HAVE_POLL @@ -1233,6 +1233,10 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) zleactive = 1; resetneeded = 1; + /* + * Start of the main zle read. + * Fully reset error conditions, including user interrupt. + */ errflag = retflag = 0; lastcol = -1; initmodifier(&zmod); @@ -1658,7 +1662,7 @@ bin_vared(char *name, char **args, Options ops, UNUSED(int func)) } if (!t || errflag) { /* error in editing */ - errflag = 0; + errflag &= ~ERRFLAG_ERROR; breaks = obreaks; if (t) zsfree(t); @@ -1778,7 +1782,7 @@ recursiveedit(UNUSED(char **args)) zrefresh(); zlecore(); - locerror = errflag; + locerror = errflag ? 1 : 0; errflag = done = eofsent = 0; return locerror; diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index d432acf7b..23286fc20 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -1041,7 +1041,7 @@ copyprevshellword(UNUSED(char **args)) int sendbreak(UNUSED(char **args)) { - errflag = 1; + errflag |= ERRFLAG_ERROR; return 1; } diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index b15d91c8e..864f804b7 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -829,7 +829,7 @@ docomplete(int lst) if (olst == COMP_EXPAND_COMPLETE && !strcmp(ol, zlemetaline)) { zlemetacs = ocs; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; if (!compfunc) { char *p; @@ -877,6 +877,19 @@ docomplete(int lst) active = 0; makecommaspecial(0); + + /* + * As a special case, we reset user interrupts here. + * That's because completion is an intensive piece of + * computation that the user might want to interrupt separately + * from anything else going on. If they do, they probably + * want to keep the line edit buffer intact. + * + * There's a race here that the user might hit ^C just + * after completion exited anyway, but that's inevitable. + */ + errflag &= ~ERRFLAG_INT; + return dat[1]; } @@ -1394,7 +1407,8 @@ get_comp_string(void) } strinend(); inpop(); - errflag = lexflags = 0; + lexflags = 0; + errflag &= ~ERRFLAG_ERROR; if (parbegin != -1) { /* We are in command or process substitution if we are not in * a $((...)). */ @@ -2917,7 +2931,7 @@ getcurcmd(void) popheap(); strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; unmetafy_line(); lexrestore(); diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index 08a32c30e..de91182b5 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -1715,7 +1715,8 @@ zlecallhook(char *name, char *arg) execzlefunc(thingy, args, 1); unrefthingy(thingy); - errflag = saverrflag; + /* Retain any user interrupt error status */ + errflag = saverrflag | (errflag & ERRFLAG_INT); retflag = savretflag; } diff --git a/Src/builtin.c b/Src/builtin.c index c2af51f2e..ad3a1925f 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -422,7 +422,7 @@ execbuiltin(LinkList args, Builtin bn) argc -= argv - argarr; if (errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; return 1; } @@ -3136,7 +3136,7 @@ bin_unset(char *name, char **argv, Options ops, int func) } } returnval = errflag; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; } else { zerrnam(name, "%s: invalid element for unset", s); returnval = 1; @@ -4242,7 +4242,7 @@ bin_print(char *name, char **args, Options ops, int func) if (*argp) { width = (int)mathevali(*argp++); if (errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; ret = 1; } } @@ -4272,7 +4272,7 @@ bin_print(char *name, char **args, Options ops, int func) if (*argp) { prec = (int)mathevali(*argp++); if (errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; ret = 1; } } @@ -4452,7 +4452,7 @@ bin_print(char *name, char **args, Options ops, int func) zlongval = (curarg) ? mathevali(curarg) : 0; if (errflag) { zlongval = 0; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; ret = 1; } print_val(zlongval) @@ -4481,7 +4481,7 @@ bin_print(char *name, char **args, Options ops, int func) } else doubleval = 0; if (errflag) { doubleval = 0; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; ret = 1; } print_val(doubleval) @@ -4494,7 +4494,7 @@ bin_print(char *name, char **args, Options ops, int func) zulongval = (curarg) ? mathevali(curarg) : 0; if (errflag) { zulongval = 0; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; ret = 1; } print_val(zulongval) @@ -4871,7 +4871,7 @@ zexit(int val, int from_where) in_exit = -1; /* * We want to do all remaining processing regardless of preceding - * errors. + * errors, even user interrupts. */ errflag = 0; @@ -5074,7 +5074,7 @@ eval(char **argv) if (fpushed) funcstack = funcstack->prev; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; scriptname = oscriptname; ineval = oineval; @@ -6101,7 +6101,7 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func) condlex = zshlex; if (errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; lexrestore(); return 1; } @@ -6278,7 +6278,7 @@ bin_let(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int func)) while (*argv) val = matheval(*argv++); /* Errors in math evaluation in let are non-fatal. */ - errflag = 0; + errflag &= ~ERRFLAG_ERROR; /* should test for fabs(val.u.d) < epsilon? */ return (val.type == MN_INTEGER) ? val.u.l == 0 : val.u.d == 0.0; } diff --git a/Src/exec.c b/Src/exec.c index a5f877191..6a7dbb1e1 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -59,7 +59,7 @@ mod_export int noerrs; /**/ int nohistsave; -/* error/break flag */ +/* error flag: bits from enum errflag_bits */ /**/ mod_export int errflag; @@ -1601,7 +1601,8 @@ execpline(Estate state, wordcode slcode, int how, int last1) (killpg(jobtab[list_pipe_job].gleader, 0) == -1 ? 2 : 1); list_pipe_pid = pid; list_pipe_start = bgtime; - nowait = errflag = 1; + nowait = 1; + errflag |= ERRFLAG_ERROR; breaks = loops; close(synch[1]); read_loop(synch[0], &dummy, 1); @@ -1634,7 +1635,10 @@ execpline(Estate state, wordcode slcode, int how, int last1) list_pipe_child = 1; opts[INTERACTIVE] = 0; if (errbrk_saved) { - errflag = prev_errflag; + /* + * Keep any user interrupt bit in errflag. + */ + errflag = prev_errflag | (errflag & ERRFLAG_INT); breaks = prev_breaks; } break; @@ -1719,12 +1723,14 @@ execpline2(Estate state, wordcode pcode, if (pipe(synch) < 0) { zerr("pipe failed: %e", errno); - lastval = errflag = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; return; } else if ((pid = zfork(&bgtime)) == -1) { close(synch[0]); close(synch[1]); - lastval = errflag = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; return; } else if (pid) { char dummy, *text; @@ -2560,7 +2566,8 @@ execcmd(Estate state, int input, int output, int how, int last1) while (next && *next == '-' && strlen(next) >= 2) { if (!firstnode(args)) { zerr("exec requires a command to execute"); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; goto done; } uremnode(args, firstnode(args)); @@ -2577,12 +2584,14 @@ execcmd(Estate state, int input, int output, int how, int last1) } else { if (!firstnode(args)) { zerr("exec requires a command to execute"); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; goto done; } if (!nextnode(firstnode(args))) { zerr("exec flag -a requires a parameter"); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; goto done; } exec_argv0 = (char *) @@ -2598,7 +2607,8 @@ execcmd(Estate state, int input, int output, int how, int last1) break; default: zerr("unknown exec flag -%c", *cmdopt); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; return; } } @@ -2661,7 +2671,8 @@ execcmd(Estate state, int input, int output, int how, int last1) } else if (!nullcmd || !*nullcmd || opts[CSHNULLCMD] || (cflags & BINF_PREFIX)) { zerr("redirection with no command"); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; return; } else if (!nullcmd || !*nullcmd || opts[SHNULLCMD]) { if (!args) @@ -2691,7 +2702,7 @@ execcmd(Estate state, int input, int output, int how, int last1) if (varspc) addvars(state, varspc, 0); if (errflag) - lastval = errflag; + lastval = 1; else lastval = cmdoutval; if (isset(XTRACE)) { @@ -2795,7 +2806,7 @@ execcmd(Estate state, int input, int output, int how, int last1) } } if (!nextnode(firstnode(args))) - errflag = 1; + errflag |= ERRFLAG_ERROR; } if (type == WC_FUNCDEF) { @@ -2940,7 +2951,8 @@ execcmd(Estate state, int input, int output, int how, int last1) } else if ((pid = zfork(&bgtime)) == -1) { close(synch[0]); close(synch[1]); - lastval = errflag = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; goto fatal; } if (pid) { @@ -3529,7 +3541,7 @@ execcmd(Estate state, int input, int output, int how, int last1) else exit(1); } - errflag = 1; + errflag |= ERRFLAG_ERROR; } } if (newxtrerr) { @@ -3759,8 +3771,10 @@ gethere(char **strp, int typ) parsestr(buf); - if (!errflag) - errflag = ef; + if (!errflag) { + /* Retain any user interrupt error */ + errflag = ef | (errflag & ERRFLAG_INT); + } } s = dupstring(buf); zfree(buf, bsiz); @@ -3854,7 +3868,7 @@ getoutput(char *cmd, int qt) return readoutput(stream, qt); } if (mpipe(pipes) < 0) { - errflag = 1; + errflag |= ERRFLAG_ERROR; cmdoutpid = 0; return NULL; } @@ -3864,7 +3878,7 @@ getoutput(char *cmd, int qt) /* fork error */ zclose(pipes[0]); zclose(pipes[1]); - errflag = 1; + errflag |= ERRFLAG_ERROR; cmdoutpid = 0; child_unblock(); return NULL; @@ -4274,7 +4288,7 @@ execcond(Estate state, UNUSED(int do_exec)) * into a shell error. */ if (stat == 2) - errflag = 1; + errflag |= ERRFLAG_ERROR; cmdpop(); if (isset(XTRACE)) { fprintf(xtrerr, " ]]\n"); @@ -4314,7 +4328,7 @@ execarith(Estate state, UNUSED(int do_exec)) fflush(xtrerr); } if (errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; return 2; } /* should test for fabs(val.u.d) < epsilon? */ @@ -4932,7 +4946,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) (name = fname)))) { zwarn("%s: function not defined by file", name); if (noreturnval) - errflag = 1; + errflag |= ERRFLAG_ERROR; else lastval = 1; goto doneshfunc; diff --git a/Src/glob.c b/Src/glob.c index b3903f2ff..82f8d626c 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -682,7 +682,7 @@ parsecomplist(char *instr) /* Now get the next path component if there is one. */ l1 = (Complist) zhalloc(sizeof *l1); if ((l1->next = parsecomplist(instr)) == NULL) { - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } l1->pat = patcompile(NULL, compflags | PAT_ANY, NULL); @@ -728,7 +728,7 @@ parsecomplist(char *instr) return (ef && !l1->next) ? NULL : l1; } } - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } @@ -1790,7 +1790,7 @@ zglob(LinkList list, LinkNode np, int nountok) insertlinknode(list, node, ostr); return; } - errflag = 0; + errflag &= ~ERRFLAG_ERROR; zerr("bad pattern: %s", ostr); return; } @@ -1873,7 +1873,8 @@ zglob(LinkList list, LinkNode np, int nountok) tmpptr->sortstrs[iexec] = tmpptr->name; } - errflag = ef; + /* Retain any user interrupt error status */ + errflag = ef | (errflag & ERRFLAG_INT); lastval = lv; } else { /* Failed, let's be safe */ @@ -3733,7 +3734,8 @@ qualsheval(char *name, UNUSED(struct stat *buf), UNUSED(off_t days), char *str) execode(prog, 1, 0, "globqual"); ret = lastval; - errflag = ef; + /* Retain any user interrupt error status */ + errflag = ef | (errflag & ERRFLAG_INT); lastval = lv; if (!(inserts = getaparam("reply")) && diff --git a/Src/hist.c b/Src/hist.c index 7fe843a4a..a0061707c 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -287,7 +287,8 @@ ihgetc(void) c = histsubchar(c); if (c < 0) { /* bad expansion */ - errflag = lexstop = 1; + lexstop = 1; + errflag |= ERRFLAG_ERROR; return ' '; } } @@ -721,7 +722,7 @@ histsubchar(int c) noerrs = 1; parse_subst_string(sline); noerrs = one; - errflag = oef; + errflag = oef | (errflag & ERRFLAG_INT); remnulargs(sline); untokenize(sline); } @@ -880,7 +881,8 @@ hbegin(int dohist) char *hf; isfirstln = isfirstch = 1; - errflag = histdone = 0; + errflag &= ~ERRFLAG_ERROR; + histdone = 0; if (!dohist) stophist = 2; else if (dohist != 2) @@ -3182,7 +3184,7 @@ bufferwords(LinkList list, char *buf, int *index, int flags) noaliases = ona; strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; nocomments = onc; noerrs = ne; lexrestore(); diff --git a/Src/init.c b/Src/init.c index 655166135..305908724 100644 --- a/Src/init.c +++ b/Src/init.c @@ -118,11 +118,24 @@ loop(int toplevel, int justonce) if (interact && toplevel) { int hstop = stophist; stophist = 3; + /* + * Reset all errors including the interrupt error status + * immediately, so preprompt runs regardless of what + * just happened. We'll reset again below as a + * precaution to ensure we get back to the command line + * no matter what. + */ + errflag = 0; preprompt(); if (stophist != 3) hbegin(1); else stophist = hstop; + /* + * Reset all errors, including user interupts. + * This is what allows ^C in an interactive shell + * to return us to the command line. + */ errflag = 0; } } @@ -178,7 +191,15 @@ loop(int toplevel, int justonce) /* The only permanent storage is from getpermtext() */ zsfree(cmdstr); - errflag = 0; + /* + * Note this does *not* remove a user interrupt error + * condition, even though we're at the top level loop: + * that would be inconsistent with the case where + * we didn't execute a preexec function. This is + * an implementation detail that an interrupting user + * does't care about. + */ + errflag &= ~ERRFLAG_ERROR; } if (stopmsg) /* unset 'you have stopped jobs' flag */ stopmsg--; @@ -689,7 +710,7 @@ init_term(void) { if (isset(INTERACTIVE)) zerr("can't find terminal definition for %s", term); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; termflags |= TERM_BAD; return 0; } else { @@ -1336,7 +1357,7 @@ source(char *s) if (prog) { pushheap(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; execode(prog, 1, 0, "filecode"); popheap(); if (errflag) @@ -1379,7 +1400,7 @@ source(char *s) lineno = oldlineno; /* our current lineno */ loops = oloops; /* the # of nested loops we are in */ dosetopt(SHINSTDIN, oldshst, 1, opts); /* SHINSTDIN option */ - errflag = 0; + errflag &= ~ERRFLAG_ERROR; if (!exit_pending) retflag = 0; scriptname = old_scriptname; diff --git a/Src/input.c b/Src/input.c index 4ac7e6ec8..9552331a9 100644 --- a/Src/input.c +++ b/Src/input.c @@ -291,7 +291,8 @@ inputline(void) } if (errflag) { free(ingetcline); - return lexstop = errflag = 1; + errflag |= ERRFLAG_ERROR; + return lexstop = 1; } if (isset(VERBOSE)) { /* Output the whole line read so far. */ diff --git a/Src/jobs.c b/Src/jobs.c index 6663a40a6..a668b07e6 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -509,7 +509,7 @@ update_job(Job jn) prev_errflag = errflag; } breaks = loops; - errflag = 1; + errflag |= ERRFLAG_INT; inerrflush(); } } else { @@ -526,7 +526,7 @@ update_job(Job jn) prev_errflag = errflag; } breaks = loops; - errflag = 1; + errflag |= ERRFLAG_INT; inerrflush(); } if (somestopped && jn->stat & STAT_SUPERJOB) @@ -581,7 +581,7 @@ update_job(Job jn) breaks = loops; } else { breaks = loops; - errflag = 1; + errflag |= ERRFLAG_INT; } check_cursh_sig(sig); } @@ -1444,12 +1444,19 @@ zwaitjob(int job, int wait_cmd) restore_queue_signals(q); return 128 + last_signal; } - /* Commenting this out makes ^C-ing a job started by a function - stop the whole function again. But I guess it will stop - something else from working properly, we have to find out - what this might be. --oberon + /* Commenting this out makes ^C-ing a job started by a function + stop the whole function again. But I guess it will stop + something else from working properly, we have to find out + what this might be. --oberon + + When attempting to separate errors and interrupts, we + assumed because of the previous comment it would be OK + to remove ERRFLAG_ERROR and leave ERRFLAG_INT set, since + that's the one related to ^C. But that doesn't work. + There's something more here we don't understand. --pws + + errflag = 0; */ - errflag = 0; */ if (subsh) { killjb(jn, SIGCONT); jn->stat &= ~STAT_STOPPED; diff --git a/Src/lex.c b/Src/lex.c index b2a05448c..4addf8033 100644 --- a/Src/lex.c +++ b/Src/lex.c @@ -385,7 +385,7 @@ lexrestore(void) ecnfunc = ln->ecnfunc; hlinesz = ln->hlinesz; toklineno = ln->toklineno; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; free(ln); unqueue_signals(); @@ -1737,7 +1737,8 @@ parse_subst_string(char *s) inpop(); DPUTS(cmdsp, "BUG: parse_subst_string: cmdstack not empty."); lexrestore(); - errflag = err; + /* Keep any interrupt error status */ + errflag = err | (errflag & ERRFLAG_INT); if (ctok == LEXERR) { untokenize(s); return 1; diff --git a/Src/loop.c b/Src/loop.c index 82d2fe31a..8bb1ec9dd 100644 --- a/Src/loop.c +++ b/Src/loop.c @@ -259,7 +259,8 @@ execselect(Estate state, UNUSED(int do_exec)) 0, ZLCON_SELECT); if (errflag) str = NULL; - errflag = oef; + /* Keep any user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); } else { str = promptexpand(prompt3, 0, NULL, NULL, NULL); zputs(str, stderr); @@ -632,6 +633,14 @@ execcase(Estate state, int do_exec) zlong try_errflag = -1; +/** + * Corresponding interrupt error status form `try' block. + */ + +/**/ +zlong +try_interrupt = -1; + /**/ zlong try_tryflag = 0; @@ -643,7 +652,7 @@ exectry(Estate state, int do_exec) Wordcode end, always; int endval; int save_retflag, save_breaks, save_contflag; - zlong save_try_errflag, save_try_tryflag; + zlong save_try_errflag, save_try_tryflag, save_try_interrupt; end = state->pc + WC_TRY_SKIP(state->pc[-1]); always = state->pc + 1 + WC_TRY_SKIP(*state->pc); @@ -670,7 +679,10 @@ exectry(Estate state, int do_exec) /* The always clause. */ save_try_errflag = try_errflag; - try_errflag = (zlong)errflag; + save_try_interrupt = try_interrupt; + try_errflag = (zlong)(errflag & ERRFLAG_ERROR); + try_interrupt = (zlong)((errflag & ERRFLAG_INT) ? 1 : 0); + /* We need to reset all errors to allow the block to execute */ errflag = 0; save_retflag = retflag; retflag = 0; @@ -682,8 +694,16 @@ exectry(Estate state, int do_exec) state->pc = always; execlist(state, 1, do_exec); - errflag = try_errflag ? 1 : 0; + if (try_errflag) + errflag |= ERRFLAG_ERROR; + else + errflag &= ~ERRFLAG_ERROR; + if (try_interrupt) + errflag |= ERRFLAG_INT; + else + errflag &= ~ERRFLAG_INT; try_errflag = save_try_errflag; + try_interrupt = save_try_interrupt; if (!retflag) retflag = save_retflag; if (!breaks) diff --git a/Src/params.c b/Src/params.c index 61edc5d08..79088d162 100644 --- a/Src/params.c +++ b/Src/params.c @@ -331,6 +331,7 @@ IPDEF5("SHLVL", &shlvl, varinteger_gsu), #define IPDEF6(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0} IPDEF6("OPTIND", &zoptind, varinteger_gsu), IPDEF6("TRY_BLOCK_ERROR", &try_errflag, varinteger_gsu), +IPDEF6("TRY_BLOCK_INTERRUPT", &try_interrupt, varinteger_gsu), #define IPDEF7(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0} #define IPDEF7U(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL|PM_UNSET},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0} @@ -2654,7 +2655,7 @@ assignsparam(char *s, char *val, int flags) if (!isident(s)) { zerr("not an identifier: %s", s); zsfree(val); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } queue_signals(); @@ -2783,7 +2784,7 @@ assignaparam(char *s, char **val, int flags) if (!isident(s)) { zerr("not an identifier: %s", s); freearray(val); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } queue_signals(); @@ -2799,7 +2800,7 @@ assignaparam(char *s, char **val, int flags) zerr("%s: attempt to set slice of associative array", v->pm->node.nam); freearray(val); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } v = NULL; @@ -2870,13 +2871,13 @@ sethparam(char *s, char **val) if (!isident(s)) { zerr("not an identifier: %s", s); freearray(val); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } if (strchr(s, '[')) { freearray(val); zerr("nested associative arrays not yet supported"); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } if (unset(EXECOPT)) @@ -2916,7 +2917,7 @@ setnparam(char *s, mnumber val) if (!isident(s)) { zerr("not an identifier: %s", s); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } if (unset(EXECOPT)) diff --git a/Src/parse.c b/Src/parse.c index 4ceeb4eaf..c1709e03a 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -71,13 +71,14 @@ struct heredocs *hdocs; #define YYERROR(O) { tok = LEXERR; ecused = (O); return 0; } #define YYERRORV(O) { tok = LEXERR; ecused = (O); return; } -#define COND_ERROR(X,Y) do { \ - zwarn(X,Y); \ - herrflush(); \ - if (noerrs != 2) \ - errflag = 1; \ - YYERROR(ecused) \ -} while(0) +#define COND_ERROR(X,Y) \ + do { \ + zwarn(X,Y); \ + herrflush(); \ + if (noerrs != 2) \ + errflag |= ERRFLAG_ERROR; \ + YYERROR(ecused) \ + } while(0) /* @@ -506,7 +507,7 @@ par_event(void) yyerror(1); herrflush(); if (noerrs != 2) - errflag = 1; + errflag |= ERRFLAG_ERROR; ecused--; return 0; } else { @@ -2339,7 +2340,7 @@ yyerror(int noerr) zwarn("parse error"); } if (!noerr && noerrs != 2) - errflag = 1; + errflag |= ERRFLAG_ERROR; } /* @@ -3031,7 +3032,7 @@ build_dump(char *nam, char *dump, char **files, int ali, int map, int flags) file = metafy(file, flen, META_REALLOC); if (!(prog = parse_string(file, 1)) || errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); zfree(file, flen); zwarnnam(nam, "can't read file: %s", *files); @@ -3141,7 +3142,7 @@ build_cur_dump(char *nam, char *dump, char **names, int match, int map, for (hn = shfunctab->nodes[i]; hn; hn = hn->next) if (cur_add_func(nam, (Shfunc) hn, lnames, progs, &hlen, &tlen, what)) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); unlink(dump); return 1; @@ -3166,7 +3167,7 @@ build_cur_dump(char *nam, char *dump, char **names, int match, int map, pattry(pprog, hn->nam) && cur_add_func(nam, (Shfunc) hn, lnames, progs, &hlen, &tlen, what)) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); unlink(dump); return 1; @@ -3177,13 +3178,13 @@ build_cur_dump(char *nam, char *dump, char **names, int match, int map, if (errflag || !(shf = (Shfunc) shfunctab->getnode(shfunctab, *names))) { zwarnnam(nam, "unknown function: %s", *names); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); unlink(dump); return 1; } if (cur_add_func(nam, shf, lnames, progs, &hlen, &tlen, what)) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); unlink(dump); return 1; @@ -3192,7 +3193,7 @@ build_cur_dump(char *nam, char *dump, char **names, int match, int map, } if (empty(progs)) { zwarnnam(nam, "no functions"); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); unlink(dump); return 1; diff --git a/Src/prompt.c b/Src/prompt.c index 0cc9ef917..3552575f3 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -192,8 +192,11 @@ promptexpand(char *s, int ns, char *rs, char *Rs, unsigned int *txtchangep) if (*s == Nularg && s[1] == '\0') *s = '\0'; - /* Ignore errors and status change in prompt substitution */ - errflag = olderr; + /* + * Ignore errors and status change in prompt substitution. + * However, keep any user interrupt error that occurred. + */ + errflag = olderr | (errflag & ERRFLAG_INT); lastval = oldval; } diff --git a/Src/signals.c b/Src/signals.c index e72850516..899f1217b 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -619,7 +619,7 @@ zhandler(int sig) zexit(SIGINT, 1); if (list_pipe || chline || simple_pline) { breaks = loops; - errflag = 1; + errflag |= ERRFLAG_INT; inerrflush(); check_cursh_sig(SIGINT); } @@ -640,6 +640,11 @@ zhandler(int sig) if (idle >= 0 && idle < tmout) alarm(tmout - idle); else { + /* + * We want to exit now. + * Cancel all errors, including a user interrupt + * which is now redundant. + */ errflag = noerrs = 0; zwarn("timeout"); stopmsg = 1; @@ -1267,7 +1272,18 @@ dotrapargs(int sig, int *sigtr, void *sigfn) !(isfunc && new_trap_return == 0)) { if (isfunc) { breaks = loops; - errflag = 1; + /* + * For SIGINT we behave the same as the default behaviour + * i.e. we set the error bit indicating an interrupt. + * We do this with SIGQUIT, too, even though we don't + * handle SIGQUIT by default. That's to try to make + * it behave a bit more like its normal behaviour when + * the trap handler has told us that's what it wants. + */ + if (sig == SIGINT || sig == SIGQUIT) + errflag |= ERRFLAG_INT; + else + errflag |= ERRFLAG_ERROR; } lastval = new_trap_return; /* return triggered */ @@ -1282,8 +1298,12 @@ dotrapargs(int sig, int *sigtr, void *sigfn) */ lastval = olastval; } - if (try_tryflag) - errflag = traperr; + if (try_tryflag) { + if (traperr) + errflag |= ERRFLAG_ERROR; + else + errflag &= ~ERRFLAG_ERROR; + } breaks += obreaks; /* return not triggered: restore old flag */ retflag = oretflag; diff --git a/Src/subst.c b/Src/subst.c index 61aa1c136..43932c256 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -2822,7 +2822,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) haserr = parse_subst_string(s); noerrs = one; if (!quoteerr) { - errflag = oef; + /* Retain user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); if (haserr) shtokenize(s); } else if (haserr || errflag) { @@ -3249,8 +3250,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) haserr = 1; } noerrs = one; - if (!quoteerr) - errflag = oef; + if (!quoteerr) { + /* Retain user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); + } if (haserr || errflag) return NULL; } @@ -3483,8 +3486,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) untokenize(*ap); } noerrs = one; - if (!quoteerr) - errflag = oef; + if (!quoteerr) { + /* Retain any user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); + } else if (haserr || errflag) { zerr("parse error in parameter value"); return NULL; @@ -3516,8 +3521,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) noerrs = 1; haserr = parse_subst_string(val); noerrs = one; - if (!quoteerr) - errflag = oef; + if (!quoteerr) { + /* Retain any user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); + } else if (haserr || errflag) { zerr("parse error in parameter value"); return NULL; @@ -4086,7 +4093,8 @@ modify(char **str, char **ptr) noerrs = 1; parse_subst_string(copy); noerrs = one; - errflag = oef; + /* Retain any user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); remnulargs(copy); untokenize(copy); } @@ -4161,7 +4169,8 @@ modify(char **str, char **ptr) noerrs = 1; parse_subst_string(*str); noerrs = one; - errflag = oef; + /* Retain any user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); remnulargs(*str); untokenize(*str); } diff --git a/Src/utils.c b/Src/utils.c index ab3d3da93..893a8ca02 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -153,7 +153,7 @@ VA_DCL if (errflag || noerrs) { if (noerrs < 2) - errflag = 1; + errflag |= ERRFLAG_ERROR; return; } @@ -161,7 +161,7 @@ VA_DCL VA_GET_ARG(ap, fmt, const char *); zwarning(NULL, fmt, ap); va_end(ap); - errflag = 1; + errflag |= ERRFLAG_ERROR; } /**/ @@ -181,7 +181,7 @@ VA_DCL VA_GET_ARG(ap, fmt, const char *); zwarning(cmd, fmt, ap); va_end(ap); - errflag = 1; + errflag |= ERRFLAG_ERROR; } /**/ @@ -330,7 +330,7 @@ zerrmsg(FILE *file, const char *fmt, va_list ap) num = va_arg(ap, int); if (num == EINTR) { fputs("interrupt\n", file); - errflag = 1; + errflag |= ERRFLAG_ERROR; return; } errmsg = strerror(num); diff --git a/Src/zsh.h b/Src/zsh.h index 031deaf3f..b366e0ff4 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -2623,6 +2623,20 @@ enum trap_state { #define IN_EVAL_TRAP() \ (intrap && !trapisfunc && traplocallevel == locallevel) +/* + * Bits in the errflag variable. + */ +enum errflag_bits { + /* + * Standard internal error bit. + */ + ERRFLAG_ERROR = 1, + /* + * User interrupt. + */ + ERRFLAG_INT = 2 +}; + /***********/ /* Sorting */ /***********/ -- cgit v1.2.3 From edb9c94025cebb853142c7e91b88c991ddd21b22 Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Fri, 12 Dec 2014 14:12:55 +0100 Subject: 33950: ignore KEYTIMEOUT for vi operators --- ChangeLog | 5 +++++ Doc/Zsh/zle.yo | 7 +++++++ Src/Zle/iwidgets.list | 12 ++++++------ Src/Zle/zle.h | 11 ++++++----- Src/Zle/zle_keymap.c | 8 +++++++- 5 files changed, 31 insertions(+), 12 deletions(-) (limited to 'Src/Zle/zle_keymap.c') diff --git a/ChangeLog b/ChangeLog index e30324894..cee9f0689 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2014-12-12 Oliver Kiddle + + * 33950: Doc/Zsh/zle.yo, Src/Zle/iwidgets.list, Src/Zle/zle.h, + Src/Zle/zle_keymap.c: ignore KEYTIMEOUT for vi operators + 2014-12-11 Peter Stephenson * 33876: etc.: Completion/Base/Core/_main_complete, diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index f95264232..d49c72020 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -1605,6 +1605,13 @@ Read a movement command from the keyboard, and kill from the cursor position to the endpoint of the movement. Then enter insert mode. If the command is tt(vi-change), change the current line. + +For compatibility with vi, if the command is tt(vi-forward-word) +or tt(vi-forward-blank-word), the whitespace after the word is not +included. If you prefer the more consistent behaviour with the +whitespace included use the following key binding: + +example(bindkey -a -s cw dwi) ) tindex(vi-change-eol) item(tt(vi-change-eol) (unbound) (C) (unbound))( diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list index 40750221e..5e598cc79 100644 --- a/Src/Zle/iwidgets.list +++ b/Src/Zle/iwidgets.list @@ -134,11 +134,11 @@ "vi-backward-blank-word-end", vibackwardblankwordend, 0 "vi-beginning-of-line", vibeginningofline, 0 "vi-caps-lock-panic", vicapslockpanic, ZLE_LASTCOL -"vi-change", vichange, ZLE_LASTCOL +"vi-change", vichange, ZLE_LASTCOL | ZLE_VIOPER "vi-change-eol", vichangeeol, 0 "vi-change-whole-line", vichangewholeline, 0 "vi-cmd-mode", vicmdmode, 0 -"vi-delete", videlete, ZLE_KEEPSUFFIX | ZLE_LASTCOL +"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-line-or-history", vidownlineorhistory, ZLE_LINEMOVE @@ -159,7 +159,7 @@ "vi-goto-mark-line", vigotomarkline, ZLE_LINEMOVE "vi-history-search-backward", vihistorysearchbackward, 0 "vi-history-search-forward", vihistorysearchforward, 0 -"vi-indent", viindent, ZLE_LASTCOL +"vi-indent", viindent, ZLE_LASTCOL | ZLE_VIOPER "vi-insert", viinsert, 0 "vi-insert-bol", viinsertbol, 0 "vi-join", vijoin, 0 @@ -168,7 +168,7 @@ "vi-match-bracket", vimatchbracket, 0 "vi-open-line-above", viopenlineabove, 0 "vi-open-line-below", viopenlinebelow, 0 -"vi-oper-swap-case", vioperswapcase, ZLE_LASTCOL +"vi-oper-swap-case", vioperswapcase, ZLE_LASTCOL | ZLE_VIOPER "vi-pound-insert", vipoundinsert, 0 "vi-put-after", viputafter, ZLE_YANKAFTER | ZLE_KEEPSUFFIX "vi-put-before", viputbefore, ZLE_YANKBEFORE | ZLE_KEEPSUFFIX @@ -185,9 +185,9 @@ "vi-substitute", visubstitute, 0 "vi-swap-case", viswapcase, ZLE_LASTCOL "vi-undo-change", viundochange, ZLE_KEEPSUFFIX -"vi-unindent", viunindent, ZLE_LASTCOL +"vi-unindent", viunindent, ZLE_LASTCOL | ZLE_VIOPER "vi-up-line-or-history", viuplineorhistory, ZLE_LINEMOVE -"vi-yank", viyank, ZLE_LASTCOL +"vi-yank", viyank, ZLE_LASTCOL | ZLE_VIOPER "vi-yank-eol", viyankeol, 0 "vi-yank-whole-line", viyankwholeline, 0 "visual-line-mode", visuallinemode, ZLE_MENUCMP | ZLE_LASTCOL diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h index a46b52ded..3c652909e 100644 --- a/Src/Zle/zle.h +++ b/Src/Zle/zle.h @@ -207,11 +207,12 @@ struct widget { #define ZLE_YANKBEFORE (1<<4) #define ZLE_YANK (ZLE_YANKAFTER | ZLE_YANKBEFORE) #define ZLE_LINEMOVE (1<<5) /* command is a line-oriented movement */ -#define ZLE_LASTCOL (1<<6) /* command maintains lastcol correctly */ -#define ZLE_KILL (1<<7) -#define ZLE_KEEPSUFFIX (1<<8) /* DON'T remove added suffix */ -#define ZLE_NOTCOMMAND (1<<9) /* widget should not alter lastcmd */ -#define ZLE_ISCOMP (1<<10) /* usable for new style completion */ +#define ZLE_VIOPER (1<<6) /* widget reads further keys so wait if prefix */ +#define ZLE_LASTCOL (1<<7) /* command maintains lastcol correctly */ +#define ZLE_KILL (1<<8) +#define ZLE_KEEPSUFFIX (1<<9) /* DON'T remove added suffix */ +#define ZLE_NOTCOMMAND (1<<10) /* widget should not alter lastcmd */ +#define ZLE_ISCOMP (1<<11) /* usable for new style completion */ /* thingies */ diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index 48f210c7e..b703ebee1 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -1444,6 +1444,7 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp) Thingy func = t_undefinedkey; char *str = NULL; int lastlen = 0, lastc = lastchar; + int timeout = 0; keybuflen = 0; keybuf[0] = 0; @@ -1461,7 +1462,7 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp) * argument to bindkey is in the correct form for the locale. * That's beyond our control. */ - while(getkeybuf(!!lastlen) != EOF) { + while(getkeybuf(timeout) != EOF) { char *s; Thingy f; int loc = !!localkeymap; @@ -1480,6 +1481,11 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp) func = f; str = s; lastc = lastchar; + + /* can be patient with vi commands that need a motion operator: * + * they wait till a key is pressed for the movement anyway */ + timeout = !(!virangeflag && !region_active && f && f->widget && + f->widget->flags & ZLE_VIOPER); } if (!ispfx) break; -- cgit v1.2.3 From 5b7950e6ef6911448a87401345eb72229b54d4e8 Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Sat, 13 Dec 2014 19:31:35 +0100 Subject: 33846: additional default vi-mode key bindings --- ChangeLog | 5 +++++ Src/Zle/iwidgets.list | 6 +++--- Src/Zle/zle_bindings.c | 4 ++-- Src/Zle/zle_keymap.c | 7 +++++++ 4 files changed, 17 insertions(+), 5 deletions(-) (limited to 'Src/Zle/zle_keymap.c') diff --git a/ChangeLog b/ChangeLog index cee9f0689..aea367d45 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2014-12-13 Oliver Kiddle + + * 33846: Src/Zle/iwidgets.list, Src/Zle/zle_bindings.c, + Src/Zle/zle_keymap.c: additional default vi-mode key bindings + 2014-12-12 Oliver Kiddle * 33950: Doc/Zsh/zle.yo, Src/Zle/iwidgets.list, Src/Zle/zle.h, diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list index 5e598cc79..b41661a7d 100644 --- a/Src/Zle/iwidgets.list +++ b/Src/Zle/iwidgets.list @@ -24,7 +24,7 @@ "backward-kill-word", backwardkillword, ZLE_KILL | ZLE_KEEPSUFFIX "backward-word", backwardword, 0 "beep", handlefeep, 0 -"beginning-of-buffer-or-history", beginningofbufferorhistory, 0 +"beginning-of-buffer-or-history", beginningofbufferorhistory, ZLE_LINEMOVE "beginning-of-history", beginningofhistory, 0 "beginning-of-line", beginningofline, 0 "beginning-of-line-hist", beginningoflinehist, 0 @@ -46,7 +46,7 @@ "down-line-or-search", downlineorsearch, ZLE_LINEMOVE | ZLE_LASTCOL "emacs-backward-word", emacsbackwardword, 0 "emacs-forward-word", emacsforwardword, 0 -"end-of-buffer-or-history", endofbufferorhistory, 0 +"end-of-buffer-or-history", endofbufferorhistory, ZLE_LINEMOVE "end-of-history", endofhistory, 0 "end-of-line", endofline, 0 "end-of-line-hist", endoflinehist, 0 @@ -143,7 +143,7 @@ "vi-digit-or-beginning-of-line", vidigitorbeginningofline, 0 "vi-down-line-or-history", vidownlineorhistory, ZLE_LINEMOVE "vi-end-of-line", viendofline, ZLE_LASTCOL -"vi-fetch-history", vifetchhistory, 0 +"vi-fetch-history", vifetchhistory, ZLE_LINEMOVE "vi-find-next-char", vifindnextchar, 0 "vi-find-next-char-skip", vifindnextcharskip, 0 "vi-find-prev-char", vifindprevchar, 0 diff --git a/Src/Zle/zle_bindings.c b/Src/Zle/zle_bindings.c index 50a29551d..e3337d032 100644 --- a/Src/Zle/zle_bindings.c +++ b/Src/Zle/zle_bindings.c @@ -308,7 +308,7 @@ int vicmdbind[128] = { /* ^O */ z_undefinedkey, /* ^P */ z_uphistory, /* ^Q */ z_undefinedkey, - /* ^R */ z_redisplay, + /* ^R */ z_redo, /* ^S */ z_undefinedkey, /* ^T */ z_undefinedkey, /* ^U */ z_undefinedkey, @@ -407,7 +407,7 @@ int vicmdbind[128] = { /* r */ z_vireplacechars, /* s */ z_visubstitute, /* t */ z_vifindnextcharskip, - /* u */ z_viundochange, + /* u */ z_undo, /* v */ z_visualmode, /* w */ z_viforwardword, /* x */ z_videletechar, diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index b703ebee1..afba592a7 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -1367,6 +1367,13 @@ default_bindings(void) bindkey(vismap, "x", refthingy(t_videlete), NULL); bindkey(vismap, "~", refthingy(t_vioperswapcase), NULL); + /* vi mode: some common vim bindings */ + bindkey(amap, "ga", refthingy(t_whatcursorposition), NULL); + 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); + /* emacs mode: arrow keys */ add_cursor_key(emap, TCUPCURSOR, t_uplineorhistory, 'A'); add_cursor_key(emap, TCDOWNCURSOR, t_downlineorhistory, 'B'); -- cgit v1.2.3 From 1e0064e58b2d03f34a36b0908325e9660362fc57 Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Sat, 13 Dec 2014 19:34:11 +0100 Subject: 33956: document key binding changes and remove ^X binding --- Doc/Zsh/zle.yo | 16 ++++++++-------- Src/Zle/zle_bindings.c | 2 +- Src/Zle/zle_keymap.c | 1 + 3 files changed, 10 insertions(+), 9 deletions(-) (limited to 'Src/Zle/zle_keymap.c') diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index d49c72020..dd8e6286a 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -1073,7 +1073,7 @@ Move backward one word, where a word is defined as a series of non-blank characters. ) tindex(vi-backward-blank-word-end) -item(tt(vi-backward-blank-word-end) (unbound) (unbound) (unbound))( +item(tt(vi-backward-blank-word-end) (unbound) (gE) (unbound))( Move to the end of the previous word, where a word is defined as a series of non-blank characters. ) @@ -1098,7 +1098,7 @@ item(tt(vi-backward-word) (unbound) (b) (unbound))( Move to the beginning of the previous word, vi-style. ) tindex(vi-backward-word-end) -item(tt(vi-backward-word-end) (unbound) (unbound) (unbound))( +item(tt(vi-backward-word-end) (unbound) (ge) (unbound))( Move to the end of the previous word, vi-style. ) tindex(beginning-of-line) @@ -1215,7 +1215,7 @@ texinode(History Control)(Modifying Text)(Movement)(Zle Widgets) subsect(History Control) startitem() tindex(beginning-of-buffer-or-history) -item(tt(beginning-of-buffer-or-history) (ESC-<) (unbound) (unbound))( +item(tt(beginning-of-buffer-or-history) (ESC-<) (gg) (unbound))( Move to the beginning of the buffer, or if already there, move to the first event in the history list. ) @@ -1728,7 +1728,7 @@ item(tt(vi-open-line-below) (unbound) (o) (unbound))( Open a line below the cursor and enter insert mode. ) tindex(vi-oper-swap-case) -item(tt(vi-oper-swap-case))( +item(tt(vi-oper-swap-case) (unbound) (g~) (unbound))( Read a movement command from the keyboard, and swap the case of all characters from the cursor position to the endpoint of the movement. @@ -2286,7 +2286,7 @@ This command is executed when a key sequence that is not bound to any command is typed. By default it beeps. ) tindex(undo) -item(tt(undo) (^_ ^Xu ^X^U) (unbound) (unbound))( +item(tt(undo) (^_ ^Xu ^X^U) (u) (unbound))( Incrementally undo the last text modification. When called from a user-defined widget, takes an optional argument indicating a previous state of the undo history as returned by the tt(UNDO_CHANGE_NO) variable; @@ -2297,11 +2297,11 @@ insert mode is reverted, the changes having been merged when command mode was selected. ) tindex(redo) -item(tt(redo))( +item(tt(redo) (unbound) (^R) (unbound))( Incrementally redo undone text modifications. ) tindex(vi-undo-change) -item(tt(vi-undo-change) (unbound) (u) (unbound))( +item(tt(vi-undo-change) (unbound) (unbound) (unbound))( Undo the last text modification. If repeated, redo the modification. ) @@ -2320,7 +2320,7 @@ following an operator, it forces the subsequent movement command to be treated as a line-wise movement. ) tindex(what-cursor-position) -item(tt(what-cursor-position) (^X=) (unbound) (unbound))( +item(tt(what-cursor-position) (^X=) (ga) (unbound))( Print the character under the cursor, its code as an octal, decimal and hexadecimal number, the current cursor position within the buffer and the column of the cursor in the current line. diff --git a/Src/Zle/zle_bindings.c b/Src/Zle/zle_bindings.c index e3337d032..2ae8c8764 100644 --- a/Src/Zle/zle_bindings.c +++ b/Src/Zle/zle_bindings.c @@ -278,7 +278,7 @@ int viinsbind[32] = { /* ^U */ z_vikillline, /* ^V */ z_viquotedinsert, /* ^W */ z_vibackwardkillword, - /* ^X */ z_selfinsert, + /* ^X */ z_undefinedkey, /* ^Y */ z_selfinsert, /* ^Z */ z_selfinsert, /* ^[ */ z_vicmdmode, diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index afba592a7..be02f3aab 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -1373,6 +1373,7 @@ default_bindings(void) bindkey(amap, "gE", refthingy(t_vibackwardblankwordend), NULL); bindkey(amap, "gg", refthingy(t_beginningofbufferorhistory), NULL); bindkey(amap, "g~", refthingy(t_vioperswapcase), NULL); + bindkey(amap, "g~~", NULL, "g~g~"); /* emacs mode: arrow keys */ add_cursor_key(emap, TCUPCURSOR, t_uplineorhistory, 'A'); -- cgit v1.2.3 From 95381783e94fa12e254df9ef8f49ea6c372ad810 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Thu, 18 Dec 2014 18:54:55 -0800 Subject: 34002: zshcalloc() in init_keymaps() --- Src/Zle/zle_keymap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Src/Zle/zle_keymap.c') diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index be02f3aab..cfef88217 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -1201,7 +1201,7 @@ init_keymaps(void) { createkeymapnamtab(); default_bindings(); - keybuf = (char *)zalloc(keybufsz); + keybuf = (char *)zshcalloc(keybufsz); lastnamed = refthingy(t_undefinedkey); } -- cgit v1.2.3 From 4508d25710de08793005923b1f91f5ae072f3945 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 17 Apr 2015 10:23:58 +0100 Subject: 34905: no parse error after keyboard interrupt. Handled generally, though only showing up in special nested cases. Also fix ZLE so it doesn't cancel the interrupt flag when not actually returning from a local keymap. --- ChangeLog | 5 +++++ Src/Zle/zle_keymap.c | 3 ++- Src/lex.c | 10 ++++++---- Src/parse.c | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) (limited to 'Src/Zle/zle_keymap.c') diff --git a/ChangeLog b/ChangeLog index ec8423c02..3b3804a99 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-04-17 Peter Stephenson + + * 34905: Src/Zle/zle_keymap.c, Src/lex.c, Src/parse.c: suppress + parse errors resulting from keyboard interruption. + 2015-04-16 Mikael Magnusson * 34902: Doc/Zsh/compsys.yo, Doc/Zsh/contrib.yo, Doc/Zsh/zle.yo: diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index cfef88217..c6fae251d 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -503,8 +503,9 @@ selectkeymap(char *name, int fb) mod_export void selectlocalmap(Keymap m) { + Keymap oldm = localkeymap; localkeymap = m; - if (!m) + if (oldm && !m) { /* * No local keymap; so we are returning to the global map. If diff --git a/Src/lex.c b/Src/lex.c index 184a54b0b..c929bb9ba 100644 --- a/Src/lex.c +++ b/Src/lex.c @@ -1558,10 +1558,12 @@ parsestr(char **s) if ((err = parsestrnoerr(s))) { untokenize(*s); - if (err > 32 && err < 127) - zerr("parse error near `%c'", err); - else - zerr("parse error"); + if (!(errflag & ERRFLAG_INT)) { + if (err > 32 && err < 127) + zerr("parse error near `%c'", err); + else + zerr("parse error"); + } } return err; } diff --git a/Src/parse.c b/Src/parse.c index 0b54a904d..91a81e1ff 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -2419,7 +2419,7 @@ yyerror(int noerr) for (t0 = 0; t0 != 20; t0++) if (!t || !t[t0] || t[t0] == '\n') break; - if (!(histdone & HISTFLAG_NOEXEC)) { + if (!(histdone & HISTFLAG_NOEXEC) && !(errflag & ERRFLAG_INT)) { if (t0 == 20) zwarn("parse error near `%l...'", t, 20); else if (t0) -- cgit v1.2.3