changeset 15279:54457fc4af0b v8.1.0648

patch 8.1.0648: custom operators can't act upon a forced motion commit https://github.com/vim/vim/commit/5976f8ff00efcb3e155a89346e44f2ad43d2405a Author: Bram Moolenaar <Bram@vim.org> Date: Thu Dec 27 23:44:44 2018 +0100 patch 8.1.0648: custom operators can't act upon a forced motion Problem: Custom operators can't act upon a forced motion. (Christian Wellenbrock) Solution: Add the forced motion to the mode() result. (Christian Brabandt, closes #3490)
author Bram Moolenaar <Bram@vim.org>
date Thu, 27 Dec 2018 23:45:05 +0100
parents 772ad94a4e03
children ef18fc59ecd5
files runtime/doc/eval.txt src/evalfunc.c src/globals.h src/normal.c src/testdir/test_mapping.vim src/version.c
diffstat 6 files changed, 73 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -6324,6 +6324,10 @@ mode([expr])	Return a string that indica
 
 		   n	    Normal, Terminal-Normal
 		   no	    Operator-pending
+		   nov	    Operator-pending (forced characterwise |o_v|)
+		   noV	    Operator-pending (forced linewise |o_V|)
+		   noCTRL-V Operator-pending (forced blockwise |o_CTRL-V|);
+		   		CTRL-V is one character
 		   niI	    Normal using |i_CTRL-O| in |Insert-mode|
 		   niR	    Normal using |i_CTRL-O| in |Replace-mode|
 		   niV	    Normal using |i_CTRL-O| in |Virtual-Replace-mode|
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -8506,7 +8506,11 @@ f_mode(typval_T *argvars, typval_T *rett
     {
 	buf[0] = 'n';
 	if (finish_op)
+	{
 	    buf[1] = 'o';
+	    // to be able to detect force-linewise/blockwise/characterwise operations
+	    buf[2] = motion_force;
+	}
 	else if (restart_edit == 'I' || restart_edit == 'R'
 							|| restart_edit == 'V')
 	{
--- a/src/globals.h
+++ b/src/globals.h
@@ -928,6 +928,7 @@ EXTERN char_u		composing_hangul_buffer[5
  * "Visual_mode"    When State is NORMAL or INSERT.
  * "finish_op"	    When State is NORMAL, after typing the operator and before
  *		    typing the motion command.
+ * "motion_force"   Last motion_force  from do_pending_operator()
  * "debug_mode"	    Debug mode.
  */
 EXTERN int	State INIT(= NORMAL);	/* This is the current state of the
@@ -938,6 +939,7 @@ EXTERN int	debug_mode INIT(= FALSE);
 
 EXTERN int	finish_op INIT(= FALSE);/* TRUE while an operator is pending */
 EXTERN long	opcount INIT(= 0);	/* count for pending operator */
+EXTERN int	motion_force INIT(= 0); // motion force for pending operator
 
 /*
  * Ex mode (Q) state
--- a/src/normal.c
+++ b/src/normal.c
@@ -1395,8 +1395,11 @@ do_pending_operator(cmdarg_T *cap, int o
 	else if (oap->motion_force == Ctrl_V)
 	{
 	    /* Change line- or characterwise motion into Visual block mode. */
-	    VIsual_active = TRUE;
-	    VIsual = oap->start;
+	    if (!VIsual_active)
+	    {
+		VIsual_active = TRUE;
+		VIsual = oap->start;
+	    }
 	    VIsual_mode = Ctrl_V;
 	    VIsual_select = FALSE;
 	    VIsual_reselect = FALSE;
@@ -2129,6 +2132,7 @@ do_pending_operator(cmdarg_T *cap, int o
 	}
 	oap->block_mode = FALSE;
 	clearop(oap);
+	motion_force = NUL;
     }
 #ifdef FEAT_LINEBREAK
     curwin->w_p_lbr = lbr_saved;
@@ -7689,7 +7693,7 @@ nv_visual(cmdarg_T *cap)
      * characterwise, linewise, or blockwise. */
     if (cap->oap->op_type != OP_NOP)
     {
-	cap->oap->motion_force = cap->cmdchar;
+	motion_force = cap->oap->motion_force = cap->cmdchar;
 	finish_op = FALSE;	/* operator doesn't finish now but later */
 	return;
     }
--- a/src/testdir/test_mapping.vim
+++ b/src/testdir/test_mapping.vim
@@ -230,3 +230,57 @@ func Test_cabbr_visual_mode()
   call assert_equal(expected, getreg(':'))
   cunabbr s
 endfunc
+
+func Test_motionforce_omap()
+  func GetCommand()
+    let g:m=mode(1)
+    let [g:lnum1, g:col1] = searchpos('-', 'Wb')
+    if g:lnum1 == 0
+        return "\<Esc>"
+    endif
+    let [g:lnum2, g:col2] = searchpos('-', 'W')
+    if g:lnum2 == 0
+        return "\<Esc>"
+    endif
+    return ":call Select()\<CR>"
+  endfunc
+  func Select()
+    call cursor([g:lnum1, g:col1])
+    exe "normal! 1 ". (strlen(g:m) == 2 ? 'v' : g:m[2])
+    call cursor([g:lnum2, g:col2])
+    execute "normal! \<BS>"
+  endfunc
+  new
+  onoremap <buffer><expr> i- GetCommand()
+  " 1) default omap mapping
+  %d_
+  call setline(1, ['aaa - bbb', 'x', 'ddd - eee'])
+  call cursor(2, 1)
+  norm di-
+  call assert_equal('no', g:m)
+  call assert_equal(['aaa -- eee'], getline(1, '$'))
+  " 2) forced characterwise operation
+  %d_
+  call setline(1, ['aaa - bbb', 'x', 'ddd - eee'])
+  call cursor(2, 1)
+  norm dvi-
+  call assert_equal('nov', g:m)
+  call assert_equal(['aaa -- eee'], getline(1, '$'))
+  " 3) forced linewise operation
+  %d_
+  call setline(1, ['aaa - bbb', 'x', 'ddd - eee'])
+  call cursor(2, 1)
+  norm dVi-
+  call assert_equal('noV', g:m)
+  call assert_equal([''], getline(1, '$'))
+  " 4) forced blockwise operation
+  %d_
+  call setline(1, ['aaa - bbb', 'x', 'ddd - eee'])
+  call cursor(2, 1)
+  exe "norm d\<C-V>i-"
+  call assert_equal("no\<C-V>", g:m)
+  call assert_equal(['aaabbb', 'x', 'dddeee'], getline(1, '$'))
+  bwipe!
+  delfunc Select
+  delfunc GetCommand
+endfunc
--- a/src/version.c
+++ b/src/version.c
@@ -800,6 +800,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    648,
+/**/
     647,
 /**/
     646,