summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--Doc/Zsh/zle.yo38
-rw-r--r--Src/Zle/zle_bindings.c4
-rw-r--r--Src/Zle/zle_keymap.c22
-rw-r--r--Src/Zle/zle_refresh.c5
-rw-r--r--Src/Zle/zle_vi.c8
-rw-r--r--Test/X02zlevi.ztst109
-rw-r--r--Test/comptest2
8 files changed, 176 insertions, 17 deletions
diff --git a/ChangeLog b/ChangeLog
index e181b3852..6fd41e4a9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2014-11-17  Oliver Kiddle  <opk@zsh.org>
 
+	* 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