forked from aniani/vim
patch 8.2.3980: if 'operatorfunc' invokes an operator Visual mode is changed
Problem: If 'operatorfunc' invokes an operator the remembered Visual mode may be changed. (Naohiro Ono) Solution: Save and restore the information for redoing the Visual area. (closes #9455)
This commit is contained in:
61
src/ops.c
61
src/ops.c
@@ -3492,6 +3492,15 @@ get_op_vcol(
|
|||||||
oap->start = curwin->w_cursor;
|
oap->start = curwin->w_cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Information for redoing the previous Visual selection.
|
||||||
|
typedef struct {
|
||||||
|
int rv_mode; // 'v', 'V', or Ctrl-V
|
||||||
|
linenr_T rv_line_count; // number of lines
|
||||||
|
colnr_T rv_vcol; // number of cols or end column
|
||||||
|
long rv_count; // count for Visual operator
|
||||||
|
int rv_arg; // extra argument
|
||||||
|
} redo_VIsual_T;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle an operator after Visual mode or when the movement is finished.
|
* Handle an operator after Visual mode or when the movement is finished.
|
||||||
* "gui_yank" is true when yanking text for the clipboard.
|
* "gui_yank" is true when yanking text for the clipboard.
|
||||||
@@ -3508,11 +3517,8 @@ do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// The visual area is remembered for redo
|
// The visual area is remembered for redo
|
||||||
static int redo_VIsual_mode = NUL; // 'v', 'V', or Ctrl-V
|
static redo_VIsual_T redo_VIsual = {NUL, 0, 0, 0,0};
|
||||||
static linenr_T redo_VIsual_line_count; // number of lines
|
|
||||||
static colnr_T redo_VIsual_vcol; // number of cols or end column
|
|
||||||
static long redo_VIsual_count; // count for Visual operator
|
|
||||||
static int redo_VIsual_arg; // extra argument
|
|
||||||
int include_line_break = FALSE;
|
int include_line_break = FALSE;
|
||||||
|
|
||||||
#if defined(FEAT_CLIPBOARD)
|
#if defined(FEAT_CLIPBOARD)
|
||||||
@@ -3621,24 +3627,24 @@ do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank)
|
|||||||
if (redo_VIsual_busy)
|
if (redo_VIsual_busy)
|
||||||
{
|
{
|
||||||
// Redo of an operation on a Visual area. Use the same size from
|
// Redo of an operation on a Visual area. Use the same size from
|
||||||
// redo_VIsual_line_count and redo_VIsual_vcol.
|
// redo_VIsual.rv_line_count and redo_VIsual.rv_vcol.
|
||||||
oap->start = curwin->w_cursor;
|
oap->start = curwin->w_cursor;
|
||||||
curwin->w_cursor.lnum += redo_VIsual_line_count - 1;
|
curwin->w_cursor.lnum += redo_VIsual.rv_line_count - 1;
|
||||||
if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
|
if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
|
||||||
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
|
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
|
||||||
VIsual_mode = redo_VIsual_mode;
|
VIsual_mode = redo_VIsual.rv_mode;
|
||||||
if (redo_VIsual_vcol == MAXCOL || VIsual_mode == 'v')
|
if (redo_VIsual.rv_vcol == MAXCOL || VIsual_mode == 'v')
|
||||||
{
|
{
|
||||||
if (VIsual_mode == 'v')
|
if (VIsual_mode == 'v')
|
||||||
{
|
{
|
||||||
if (redo_VIsual_line_count <= 1)
|
if (redo_VIsual.rv_line_count <= 1)
|
||||||
{
|
{
|
||||||
validate_virtcol();
|
validate_virtcol();
|
||||||
curwin->w_curswant =
|
curwin->w_curswant =
|
||||||
curwin->w_virtcol + redo_VIsual_vcol - 1;
|
curwin->w_virtcol + redo_VIsual.rv_vcol - 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
curwin->w_curswant = redo_VIsual_vcol;
|
curwin->w_curswant = redo_VIsual.rv_vcol;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -3646,9 +3652,9 @@ do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank)
|
|||||||
}
|
}
|
||||||
coladvance(curwin->w_curswant);
|
coladvance(curwin->w_curswant);
|
||||||
}
|
}
|
||||||
cap->count0 = redo_VIsual_count;
|
cap->count0 = redo_VIsual.rv_count;
|
||||||
if (redo_VIsual_count != 0)
|
if (redo_VIsual.rv_count != 0)
|
||||||
cap->count1 = redo_VIsual_count;
|
cap->count1 = redo_VIsual.rv_count;
|
||||||
else
|
else
|
||||||
cap->count1 = 1;
|
cap->count1 = 1;
|
||||||
}
|
}
|
||||||
@@ -3750,7 +3756,7 @@ do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank)
|
|||||||
|
|
||||||
if (VIsual_active || redo_VIsual_busy)
|
if (VIsual_active || redo_VIsual_busy)
|
||||||
{
|
{
|
||||||
get_op_vcol(oap, redo_VIsual_vcol, TRUE);
|
get_op_vcol(oap, redo_VIsual.rv_vcol, TRUE);
|
||||||
|
|
||||||
if (!redo_VIsual_busy && !gui_yank)
|
if (!redo_VIsual_busy && !gui_yank)
|
||||||
{
|
{
|
||||||
@@ -3822,11 +3828,11 @@ do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank)
|
|||||||
}
|
}
|
||||||
if (!redo_VIsual_busy)
|
if (!redo_VIsual_busy)
|
||||||
{
|
{
|
||||||
redo_VIsual_mode = resel_VIsual_mode;
|
redo_VIsual.rv_mode = resel_VIsual_mode;
|
||||||
redo_VIsual_vcol = resel_VIsual_vcol;
|
redo_VIsual.rv_vcol = resel_VIsual_vcol;
|
||||||
redo_VIsual_line_count = resel_VIsual_line_count;
|
redo_VIsual.rv_line_count = resel_VIsual_line_count;
|
||||||
redo_VIsual_count = cap->count0;
|
redo_VIsual.rv_count = cap->count0;
|
||||||
redo_VIsual_arg = cap->arg;
|
redo_VIsual.rv_arg = cap->arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4114,13 +4120,22 @@ do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_FUNCTION:
|
case OP_FUNCTION:
|
||||||
|
{
|
||||||
|
redo_VIsual_T save_redo_VIsual = redo_VIsual;
|
||||||
|
|
||||||
#ifdef FEAT_LINEBREAK
|
#ifdef FEAT_LINEBREAK
|
||||||
// Restore linebreak, so that when the user edits it looks as
|
// Restore linebreak, so that when the user edits it looks as
|
||||||
// before.
|
// before.
|
||||||
curwin->w_p_lbr = lbr_saved;
|
curwin->w_p_lbr = lbr_saved;
|
||||||
#endif
|
#endif
|
||||||
op_function(oap); // call 'operatorfunc'
|
// call 'operatorfunc'
|
||||||
|
op_function(oap);
|
||||||
|
|
||||||
|
// Restore the info for redoing Visual mode, the function may
|
||||||
|
// invoke another operator and unintentionally change it.
|
||||||
|
redo_VIsual = save_redo_VIsual;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case OP_INSERT:
|
case OP_INSERT:
|
||||||
case OP_APPEND:
|
case OP_APPEND:
|
||||||
@@ -4216,7 +4231,7 @@ do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank)
|
|||||||
#ifdef FEAT_LINEBREAK
|
#ifdef FEAT_LINEBREAK
|
||||||
curwin->w_p_lbr = lbr_saved;
|
curwin->w_p_lbr = lbr_saved;
|
||||||
#endif
|
#endif
|
||||||
op_addsub(oap, cap->count1, redo_VIsual_arg);
|
op_addsub(oap, cap->count1, redo_VIsual.rv_arg);
|
||||||
VIsual_active = FALSE;
|
VIsual_active = FALSE;
|
||||||
}
|
}
|
||||||
check_cursor_col();
|
check_cursor_col();
|
||||||
|
@@ -464,6 +464,10 @@ func OperatorfuncRedo(_)
|
|||||||
let g:opfunc_count = v:count
|
let g:opfunc_count = v:count
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Underscorize(_)
|
||||||
|
normal! '[V']r_
|
||||||
|
endfunc
|
||||||
|
|
||||||
func Test_normal09c_operatorfunc()
|
func Test_normal09c_operatorfunc()
|
||||||
" Test redoing operatorfunc
|
" Test redoing operatorfunc
|
||||||
new
|
new
|
||||||
@@ -477,6 +481,16 @@ func Test_normal09c_operatorfunc()
|
|||||||
|
|
||||||
bw!
|
bw!
|
||||||
unlet g:opfunc_count
|
unlet g:opfunc_count
|
||||||
|
|
||||||
|
" Test redoing Visual mode
|
||||||
|
set operatorfunc=Underscorize
|
||||||
|
new
|
||||||
|
call setline(1, ['first', 'first', 'third', 'third', 'second'])
|
||||||
|
normal! 1GVjr_
|
||||||
|
normal! 5G.
|
||||||
|
normal! 3G.
|
||||||
|
call assert_equal(['_____', '_____', '_____', '_____', '______'], getline(1, '$'))
|
||||||
|
bwipe!
|
||||||
set operatorfunc=
|
set operatorfunc=
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
@@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
3980,
|
||||||
/**/
|
/**/
|
||||||
3979,
|
3979,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user