To: vim_dev@googlegroups.com Subject: Patch 8.2.3980 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 -- Bram@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 ///