about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--Doc/Zsh/zle.yo8
-rw-r--r--Src/Zle/iwidgets.list2
-rw-r--r--Src/Zle/zle.h2
-rw-r--r--Src/Zle/zle_move.c12
-rw-r--r--Src/Zle/zle_vi.c13
-rw-r--r--Test/X02zlevi.ztst21
7 files changed, 59 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index fd6a49f22..b8af2130c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2014-12-08  Oliver Kiddle  <opk@zsh.org>
+
+	* 33924: Doc/Zsh/zle.yo, Src/Zle/iwidgets.list, Src/Zle/zle.h,
+	Src/Zle/zle_move.c, Src/Zle/zle_vi.c, Test/X02zlevi.ztst:
+	allow vi line/characterwise mode to be forced
+
 2014-12-08  Peter Stephenson  <p.stephenson@samsung.com>
 
 	* 33927: Completion/Unix/Command/_nm: .elf files and
diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index 3693ec9d5..f95264232 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -2301,12 +2301,16 @@ 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.
+currently enabled then it is changed to being character-wise. If used
+following an operator, it forces the subsequent movement command to be
+treated as a character-wise movement.
 )
 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.
+visual mode is currently enabled then it is changed to being line-wise. If used
+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))(
diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list
index 1a664e5e8..40750221e 100644
--- a/Src/Zle/iwidgets.list
+++ b/Src/Zle/iwidgets.list
@@ -156,7 +156,7 @@
 "vi-forward-word-end", viforwardwordend, 0
 "vi-goto-column", vigotocolumn, 0
 "vi-goto-mark", vigotomark, 0
-"vi-goto-mark-line", vigotomarkline, 0
+"vi-goto-mark-line", vigotomarkline, ZLE_LINEMOVE
 "vi-history-search-backward", vihistorysearchbackward, 0
 "vi-history-search-forward", vihistorysearchforward, 0
 "vi-indent", viindent, ZLE_LASTCOL
diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h
index 8a85ee342..a46b52ded 100644
--- a/Src/Zle/zle.h
+++ b/Src/Zle/zle.h
@@ -243,6 +243,8 @@ struct modifier {
 #define MOD_VIAPP (1<<3)   /* appending to the vi cut buffer */
 #define MOD_NEG   (1<<4)   /* last command was negate argument */
 #define MOD_NULL  (1<<5)   /* throw away text for the vi cut buffer */
+#define MOD_CHAR  (1<<6)   /* force character-wise movement */
+#define MOD_LINE  (1<<7)   /* force line-wise movement */
 
 /* current modifier status */
 
diff --git a/Src/Zle/zle_move.c b/Src/Zle/zle_move.c
index 939cfb1d0..d751c4333 100644
--- a/Src/Zle/zle_move.c
+++ b/Src/Zle/zle_move.c
@@ -511,6 +511,12 @@ exchangepointandmark(UNUSED(char **args))
 int
 visualmode(UNUSED(char **args))
 {
+    if (virangeflag) {
+	prefixflag = 1;
+	zmod.flags &= ~MOD_LINE;
+	zmod.flags |= MOD_CHAR;
+	return 0;
+    }
     switch (region_active) {
     case 1:
 	region_active = 0;
@@ -529,6 +535,12 @@ visualmode(UNUSED(char **args))
 int
 visuallinemode(UNUSED(char **args))
 {
+    if (virangeflag) {
+	prefixflag = 1;
+	zmod.flags &= ~MOD_CHAR;
+	zmod.flags |= MOD_LINE;
+	return 0;
+    }
     switch (region_active) {
     case 2:
 	region_active = 0;
diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c
index 249e38f15..1a11ca7d5 100644
--- a/Src/Zle/zle_vi.c
+++ b/Src/Zle/zle_vi.c
@@ -259,15 +259,24 @@ getvirange(int wf)
     /* Was it a line-oriented move?  If so, the command will have set *
      * the vilinerange flag.  In this case, entire lines are taken,   *
      * rather than just the sequence of characters delimited by pos   *
-     * and zlecs.  The terminating newline is left out of the range,     *
+     * and zlecs.  The terminating newline is left out of the range,  *
      * which the real command must deal with appropriately.  At this  *
      * point we just need to make the range encompass entire lines.   */
-    if(vilinerange) {
+    vilinerange = (zmod.flags & MOD_LINE) ||
+	    (vilinerange && !(zmod.flags & MOD_CHAR));
+    if (vilinerange) {
 	int newcs = findbol();
 	lastcol = zlecs - newcs;
 	zlecs = pos;
 	pos = findeol();
 	zlecs = newcs;
+    } else if (!visual) {
+	/* for a character-wise move don't include a newline at the *
+	 * end of the range                                         */
+	int prev = pos;
+	DECPOS(prev);
+	if (zleline[prev] == ZWC('\n'))
+	    pos = prev;
     }
     return pos;
 }
diff --git a/Test/X02zlevi.ztst b/Test/X02zlevi.ztst
index 4f2f3193d..7bb35d52f 100644
--- a/Test/X02zlevi.ztst
+++ b/Test/X02zlevi.ztst
@@ -287,6 +287,27 @@
 >BUFFER: one wo
 >CURSOR: 2
 
+  zletest $'keepnot\eo  unwanted\ekhhcvj '
+0:force character-wise change to join lines
+>BUFFER: keep wanted
+>CURSOR: 5
+
+  zletest $'}\eOkeep{del\eF{dvj'
+0:character-wise delete to beginning of line leaves the newline'
+>BUFFER: keep
+>}
+>CURSOR: 3
+
+  zletest $'keep\eOdel\edVh'
+0:force line-wise delete of line
+>BUFFER: keep
+>CURSOR: 0
+
+  zletest $'one two three\eFwdVawaX'
+0:line-wise force of a text object
+>BUFFER: X
+>CURSOR: 1
+
   zletest $'one two\evbcx'
 0:change selection
 >BUFFER: one x