aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/eval.txt52
-rw-r--r--src/nvim/globals.h2
-rw-r--r--src/nvim/normal.c11
-rw-r--r--src/nvim/state.c4
-rw-r--r--src/nvim/testdir/test_mapping.vim54
5 files changed, 95 insertions, 28 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 7b463aa6ca..425dcede8b 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -5741,29 +5741,35 @@ mode([expr]) Return a string that indicates the current mode.
a non-empty String (|non-zero-arg|), then the full mode is
returned, otherwise only the first letter is returned.
- n Normal
- no Operator-pending
- v Visual by character
- V Visual by line
- CTRL-V Visual blockwise
- s Select by character
- S Select by line
- CTRL-S Select blockwise
- i Insert
- ic Insert mode completion |compl-generic|
- ix Insert mode |i_CTRL-X| completion
- R Replace |R|
- Rc Replace mode completion |compl-generic|
- Rv Virtual Replace |gR|
- Rx Replace mode |i_CTRL-X| completion
- c Command-line editing
- cv Vim Ex mode |gQ|
- ce Normal Ex mode |Q|
- r Hit-enter prompt
- rm The -- more -- prompt
- r? A |:confirm| query of some sort
- ! Shell or external command is executing
- t Terminal mode: keys go to the job
+ n 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|)
+ 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|
+ v Visual by character
+ V Visual by line
+ CTRL-V Visual blockwise
+ s Select by character
+ S Select by line
+ CTRL-S Select blockwise
+ i Insert
+ ic Insert mode completion |compl-generic|
+ ix Insert mode |i_CTRL-X| completion
+ R Replace |R|
+ Rc Replace mode completion |compl-generic|
+ Rv Virtual Replace |gR|
+ Rx Replace mode |i_CTRL-X| completion
+ c Command-line editing
+ cv Vim Ex mode |gQ|
+ ce Normal Ex mode |Q|
+ r Hit-enter prompt
+ rm The -- more -- prompt
+ r? |:confirm| query of some sort
+ ! Shell or external command is executing
+ t Terminal mode: keys go to the job
This is useful in the 'statusline' option or when used
with |remote_expr()| In most other places it always returns
"c" or "n".
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index f2bd6408e8..f749c119cd 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -661,11 +661,13 @@ EXTERN int* (*iconv_errno)(void);
/// 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()
EXTERN int State INIT(= NORMAL); // This is the current state of the
// command interpreter.
EXTERN bool 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
EXTERN int exmode_active INIT(= 0); // Zero, EXMODE_NORMAL or EXMODE_VIM.
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 705dea4e88..29c5d27258 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -1445,8 +1445,10 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
oap->motion_type = kMTCharWise;
} 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;
@@ -2039,6 +2041,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
curwin->w_cursor = old_cursor;
}
clearop(oap);
+ motion_force = NUL;
}
curwin->w_p_lbr = lbr_saved;
}
@@ -6389,8 +6392,8 @@ static void nv_visual(cmdarg_T *cap)
/* 'v', 'V' and CTRL-V can be used while an operator is pending to make it
* characterwise, linewise, or blockwise. */
if (cap->oap->op_type != OP_NOP) {
- cap->oap->motion_force = cap->cmdchar;
- finish_op = false; /* operator doesn't finish now but later */
+ motion_force = cap->oap->motion_force = cap->cmdchar;
+ finish_op = false; // operator doesn't finish now but later
return;
}
diff --git a/src/nvim/state.c b/src/nvim/state.c
index d75f4038ae..bfd73050c3 100644
--- a/src/nvim/state.c
+++ b/src/nvim/state.c
@@ -113,7 +113,7 @@ int get_real_state(void)
/// @returns[allocated] mode string
char *get_mode(void)
{
- char *buf = xcalloc(3, sizeof(char));
+ char *buf = xcalloc(4, sizeof(char));
if (VIsual_active) {
if (VIsual_select) {
@@ -160,6 +160,8 @@ char *get_mode(void)
buf[0] = 'n';
if (finish_op) {
buf[1] = 'o';
+ // to be able to detect force-linewise/blockwise/characterwise operations
+ buf[2] = (char)motion_force;
}
}
diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim
index 247c01c98d..32593a423a 100644
--- a/src/nvim/testdir/test_mapping.vim
+++ b/src/nvim/testdir/test_mapping.vim
@@ -230,3 +230,57 @@ func Test_abbreviation_CR()
delfunc Eatchar
bw!
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