Patch 8.2.3980
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)
Files: src/ops.c, src/testdir/test_normal.vim
*** ../vim-8.2.3979/src/ops.c 2021-12-31 22:48:56.587368898 +0000
--- src/ops.c 2022-01-02 12:57:17.795428838 +0000
***************
*** 3492,3497 ****
--- 3492,3506 ----
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.
* "gui_yank" is true when yanking text for the clipboard.
***************
*** 3508,3518 ****
#endif
// The visual area is remembered for redo
! static int redo_VIsual_mode = NUL; // 'v', 'V', or Ctrl-V
! 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;
#if defined(FEAT_CLIPBOARD)
--- 3517,3524 ----
#endif
// The visual area is remembered for redo
! static redo_VIsual_T redo_VIsual = {NUL, 0, 0, 0,0};
!
int include_line_break = FALSE;
#if defined(FEAT_CLIPBOARD)
***************
*** 3621,3644 ****
if (redo_VIsual_busy)
{
// Redo of an operation on a Visual area. Use the same size from
! // redo_VIsual_line_count and redo_VIsual_vcol.
oap->start = curwin->w_cursor;
! curwin->w_cursor.lnum += redo_VIsual_line_count - 1;
if (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;
! if (redo_VIsual_vcol == MAXCOL || VIsual_mode == 'v')
{
if (VIsual_mode == 'v')
{
! if (redo_VIsual_line_count <= 1)
{
validate_virtcol();
curwin->w_curswant =
! curwin->w_virtcol + redo_VIsual_vcol - 1;
}
else
! curwin->w_curswant = redo_VIsual_vcol;
}
else
{
--- 3627,3650 ----
if (redo_VIsual_busy)
{
// Redo of an operation on a Visual area. Use the same size from
! // redo_VIsual.rv_line_count and redo_VIsual.rv_vcol.
oap->start = curwin->w_cursor;
! curwin->w_cursor.lnum += redo_VIsual.rv_line_count - 1;
if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
! VIsual_mode = redo_VIsual.rv_mode;
! if (redo_VIsual.rv_vcol == MAXCOL || VIsual_mode == 'v')
{
if (VIsual_mode == 'v')
{
! if (redo_VIsual.rv_line_count <= 1)
{
validate_virtcol();
curwin->w_curswant =
! curwin->w_virtcol + redo_VIsual.rv_vcol - 1;
}
else
! curwin->w_curswant = redo_VIsual.rv_vcol;
}
else
{
***************
*** 3646,3654 ****
}
coladvance(curwin->w_curswant);
}
! cap->count0 = redo_VIsual_count;
! if (redo_VIsual_count != 0)
! cap->count1 = redo_VIsual_count;
else
cap->count1 = 1;
}
--- 3652,3660 ----
}
coladvance(curwin->w_curswant);
}
! cap->count0 = redo_VIsual.rv_count;
! if (redo_VIsual.rv_count != 0)
! cap->count1 = redo_VIsual.rv_count;
else
cap->count1 = 1;
}
***************
*** 3750,3756 ****
if (VIsual_active || redo_VIsual_busy)
{
! get_op_vcol(oap, redo_VIsual_vcol, TRUE);
if (!redo_VIsual_busy && !gui_yank)
{
--- 3756,3762 ----
if (VIsual_active || redo_VIsual_busy)
{
! get_op_vcol(oap, redo_VIsual.rv_vcol, TRUE);
if (!redo_VIsual_busy && !gui_yank)
{
***************
*** 3822,3832 ****
}
if (!redo_VIsual_busy)
{
! redo_VIsual_mode = resel_VIsual_mode;
! redo_VIsual_vcol = resel_VIsual_vcol;
! redo_VIsual_line_count = resel_VIsual_line_count;
! redo_VIsual_count = cap->count0;
! redo_VIsual_arg = cap->arg;
}
}
--- 3828,3838 ----
}
if (!redo_VIsual_busy)
{
! redo_VIsual.rv_mode = resel_VIsual_mode;
! redo_VIsual.rv_vcol = resel_VIsual_vcol;
! redo_VIsual.rv_line_count = resel_VIsual_line_count;
! redo_VIsual.rv_count = cap->count0;
! redo_VIsual.rv_arg = cap->arg;
}
}
***************
*** 4114,4126 ****
break;
case OP_FUNCTION:
#ifdef FEAT_LINEBREAK
! // Restore linebreak, so that when the user edits it looks as
! // before.
! curwin->w_p_lbr = lbr_saved;
#endif
! op_function(oap); // call 'operatorfunc'
! break;
case OP_INSERT:
case OP_APPEND:
--- 4120,4141 ----
break;
case OP_FUNCTION:
+ {
+ redo_VIsual_T save_redo_VIsual = redo_VIsual;
+
#ifdef FEAT_LINEBREAK
! // Restore linebreak, so that when the user edits it looks as
! // before.
! curwin->w_p_lbr = lbr_saved;
#endif
! // 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;
! }
case OP_INSERT:
case OP_APPEND:
***************
*** 4216,4222 ****
#ifdef FEAT_LINEBREAK
curwin->w_p_lbr = lbr_saved;
#endif
! op_addsub(oap, cap->count1, redo_VIsual_arg);
VIsual_active = FALSE;
}
check_cursor_col();
--- 4231,4237 ----
#ifdef FEAT_LINEBREAK
curwin->w_p_lbr = lbr_saved;
#endif
! op_addsub(oap, cap->count1, redo_VIsual.rv_arg);
VIsual_active = FALSE;
}
check_cursor_col();
*** ../vim-8.2.3979/src/testdir/test_normal.vim 2022-01-01 14:59:39.543684481 +0000
--- src/testdir/test_normal.vim 2022-01-02 13:02:16.408108335 +0000
***************
*** 464,469 ****
--- 464,473 ----
let g:opfunc_count = v:count
endfunc
+ func Underscorize(_)
+ normal! '[V']r_
+ endfunc
+
func Test_normal09c_operatorfunc()
" Test redoing operatorfunc
new
***************
*** 477,482 ****
--- 481,496 ----
bw!
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=
endfunc
*** ../vim-8.2.3979/src/version.c 2022-01-02 12:05:59.033607215 +0000
--- src/version.c 2022-01-02 13:03:23.304183419 +0000
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 3980,
/**/
--
I'm in shape. Round IS a shape.
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///