mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:8.1.0648: custom operators can't act upon 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 vim/vim#3490)
5976f8ff00
closes #8667
closes #9476
Christian Wellenbrock:
> For (most) built in text objects it's possible to force operation on
> them to be linewise, for example by using `dVab` (`:h o_V`,
> `motion_force`). When using custom text objects (defined as mappings
> by plugins for example), this doesn't currently work.
>
> Example:
>
> onoremap x viw
>
> Open a file with a few lines each containing some words. With the
> cursor on any word, try:
>
> 1. `dw` (builtin) deletes some characters
> 2. `dVw` (builtin) deletes linewise
> 3. `dx` (from mapping) deletes some characters
> 4. `dVx` (from mapping) deletes some characters, but should delete
> linewise
ref: https://github.com/wellle/targets.vim/issues/214
ref: https://gitter.im/neovim/neovim?at=5b379ff7f1664406610e7483
This commit is contained in:
parent
1ca2c8950f
commit
57c7e1d4a0
@ -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
|
a non-empty String (|non-zero-arg|), then the full mode is
|
||||||
returned, otherwise only the first letter is returned.
|
returned, otherwise only the first letter is returned.
|
||||||
|
|
||||||
n Normal
|
n Normal
|
||||||
no Operator-pending
|
no Operator-pending
|
||||||
v Visual by character
|
nov Operator-pending (forced characterwise |o_v|)
|
||||||
V Visual by line
|
noV Operator-pending (forced linewise |o_V|)
|
||||||
CTRL-V Visual blockwise
|
noCTRL-V Operator-pending (forced blockwise |o_CTRL-V|)
|
||||||
s Select by character
|
niI Normal using |i_CTRL-O| in |Insert-mode|
|
||||||
S Select by line
|
niR Normal using |i_CTRL-O| in |Replace-mode|
|
||||||
CTRL-S Select blockwise
|
niV Normal using |i_CTRL-O| in |Virtual-Replace-mode|
|
||||||
i Insert
|
v Visual by character
|
||||||
ic Insert mode completion |compl-generic|
|
V Visual by line
|
||||||
ix Insert mode |i_CTRL-X| completion
|
CTRL-V Visual blockwise
|
||||||
R Replace |R|
|
s Select by character
|
||||||
Rc Replace mode completion |compl-generic|
|
S Select by line
|
||||||
Rv Virtual Replace |gR|
|
CTRL-S Select blockwise
|
||||||
Rx Replace mode |i_CTRL-X| completion
|
i Insert
|
||||||
c Command-line editing
|
ic Insert mode completion |compl-generic|
|
||||||
cv Vim Ex mode |gQ|
|
ix Insert mode |i_CTRL-X| completion
|
||||||
ce Normal Ex mode |Q|
|
R Replace |R|
|
||||||
r Hit-enter prompt
|
Rc Replace mode completion |compl-generic|
|
||||||
rm The -- more -- prompt
|
Rv Virtual Replace |gR|
|
||||||
r? A |:confirm| query of some sort
|
Rx Replace mode |i_CTRL-X| completion
|
||||||
! Shell or external command is executing
|
c Command-line editing
|
||||||
t Terminal mode: keys go to the job
|
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
|
This is useful in the 'statusline' option or when used
|
||||||
with |remote_expr()| In most other places it always returns
|
with |remote_expr()| In most other places it always returns
|
||||||
"c" or "n".
|
"c" or "n".
|
||||||
|
@ -661,11 +661,13 @@ EXTERN int* (*iconv_errno)(void);
|
|||||||
/// Visual_mode: When State is NORMAL or INSERT.
|
/// Visual_mode: When State is NORMAL or INSERT.
|
||||||
/// finish_op : When State is NORMAL, after typing the operator and
|
/// finish_op : When State is NORMAL, after typing the operator and
|
||||||
/// before typing the motion command.
|
/// 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
|
EXTERN int State INIT(= NORMAL); // This is the current state of the
|
||||||
// command interpreter.
|
// command interpreter.
|
||||||
|
|
||||||
EXTERN bool finish_op INIT(= false); // true while an operator is pending
|
EXTERN bool finish_op INIT(= false); // true while an operator is pending
|
||||||
EXTERN long opcount INIT(= 0); // count for pending operator
|
EXTERN long opcount INIT(= 0); // count for pending operator
|
||||||
|
EXTERN int motion_force INIT(=0); // motion force for pending operator
|
||||||
|
|
||||||
// Ex Mode (Q) state
|
// Ex Mode (Q) state
|
||||||
EXTERN int exmode_active INIT(= 0); // Zero, EXMODE_NORMAL or EXMODE_VIM.
|
EXTERN int exmode_active INIT(= 0); // Zero, EXMODE_NORMAL or EXMODE_VIM.
|
||||||
|
@ -1445,8 +1445,10 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
|
|||||||
oap->motion_type = kMTCharWise;
|
oap->motion_type = kMTCharWise;
|
||||||
} else if (oap->motion_force == Ctrl_V) {
|
} else if (oap->motion_force == Ctrl_V) {
|
||||||
// Change line- or characterwise motion into Visual block mode.
|
// Change line- or characterwise motion into Visual block mode.
|
||||||
VIsual_active = true;
|
if (!VIsual_active) {
|
||||||
VIsual = oap->start;
|
VIsual_active = true;
|
||||||
|
VIsual = oap->start;
|
||||||
|
}
|
||||||
VIsual_mode = Ctrl_V;
|
VIsual_mode = Ctrl_V;
|
||||||
VIsual_select = false;
|
VIsual_select = false;
|
||||||
VIsual_reselect = 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;
|
curwin->w_cursor = old_cursor;
|
||||||
}
|
}
|
||||||
clearop(oap);
|
clearop(oap);
|
||||||
|
motion_force = NUL;
|
||||||
}
|
}
|
||||||
curwin->w_p_lbr = lbr_saved;
|
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
|
/* 'v', 'V' and CTRL-V can be used while an operator is pending to make it
|
||||||
* characterwise, linewise, or blockwise. */
|
* characterwise, linewise, or blockwise. */
|
||||||
if (cap->oap->op_type != OP_NOP) {
|
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 */
|
finish_op = false; // operator doesn't finish now but later
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ int get_real_state(void)
|
|||||||
/// @returns[allocated] mode string
|
/// @returns[allocated] mode string
|
||||||
char *get_mode(void)
|
char *get_mode(void)
|
||||||
{
|
{
|
||||||
char *buf = xcalloc(3, sizeof(char));
|
char *buf = xcalloc(4, sizeof(char));
|
||||||
|
|
||||||
if (VIsual_active) {
|
if (VIsual_active) {
|
||||||
if (VIsual_select) {
|
if (VIsual_select) {
|
||||||
@ -160,6 +160,8 @@ char *get_mode(void)
|
|||||||
buf[0] = 'n';
|
buf[0] = 'n';
|
||||||
if (finish_op) {
|
if (finish_op) {
|
||||||
buf[1] = 'o';
|
buf[1] = 'o';
|
||||||
|
// to be able to detect force-linewise/blockwise/characterwise operations
|
||||||
|
buf[2] = (char)motion_force;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,3 +230,57 @@ func Test_abbreviation_CR()
|
|||||||
delfunc Eatchar
|
delfunc Eatchar
|
||||||
bw!
|
bw!
|
||||||
endfunc
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user