diff options
author | zeertzjq <zeertzjq@outlook.com> | 2022-07-05 18:48:26 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-05 18:48:26 +0800 |
commit | 2536bde6c9ef5f0a94c0d3789a18a14de6a0a666 (patch) | |
tree | a6318dfe0cd8a43ca6c4b6e57d4c68454285e77f /src | |
parent | d0835617facc98daf79318e26d41669bb2ce1a6b (diff) | |
parent | 785422ad54b6ce97cdec994862725b2846775e88 (diff) | |
download | rneovim-2536bde6c9ef5f0a94c0d3789a18a14de6a0a666.tar.gz rneovim-2536bde6c9ef5f0a94c0d3789a18a14de6a0a666.tar.bz2 rneovim-2536bde6c9ef5f0a94c0d3789a18a14de6a0a666.zip |
Merge pull request #19232 from zeertzjq/vim-8.2.2904
vim-patch:8.2.{2904,3644.3980,3990}: three Normal mode fixes
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/normal.c | 25 | ||||
-rw-r--r-- | src/nvim/ops.c | 70 | ||||
-rw-r--r-- | src/nvim/testdir/test_normal.vim | 67 |
3 files changed, 129 insertions, 33 deletions
diff --git a/src/nvim/normal.c b/src/nvim/normal.c index c7f7b569e7..ed624c0c9f 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -2494,21 +2494,30 @@ static void prep_redo_cmd(cmdarg_T *cap) /// Note that only the last argument can be a multi-byte char. void prep_redo(int regname, long num, int cmd1, int cmd2, int cmd3, int cmd4, int cmd5) { + prep_redo_num2(regname, num, cmd1, cmd2, 0L, cmd3, cmd4, cmd5); +} + +/// Prepare for redo of any command with extra count after "cmd2". +void prep_redo_num2(int regname, long num1, int cmd1, int cmd2, long num2, int cmd3, int cmd4, + int cmd5) +{ ResetRedobuff(); if (regname != 0) { // yank from specified buffer AppendCharToRedobuff('"'); AppendCharToRedobuff(regname); } - if (num) { - AppendNumberToRedobuff(num); + if (num1 != 0) { + AppendNumberToRedobuff(num1); } - if (cmd1 != NUL) { AppendCharToRedobuff(cmd1); } if (cmd2 != NUL) { AppendCharToRedobuff(cmd2); } + if (num2 != 0) { + AppendNumberToRedobuff(num2); + } if (cmd3 != NUL) { AppendCharToRedobuff(cmd3); } @@ -6157,6 +6166,16 @@ static void nv_g_cmd(cmdarg_T *cap) i = curwin->w_leftcol + curwin->w_width_inner - col_off - 1; coladvance((colnr_T)i); + // if the character doesn't fit move one back + if (curwin->w_cursor.col > 0 && utf_ptr2cells((const char *)get_cursor_pos_ptr()) > 1) { + colnr_T vcol; + + getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &vcol); + if (vcol >= curwin->w_leftcol + curwin->w_width - col_off) { + curwin->w_cursor.col--; + } + } + // Make sure we stick in this column. validate_virtcol(); curwin->w_curswant = curwin->w_virtcol; diff --git a/src/nvim/ops.c b/src/nvim/ops.c index f2859bf707..2f29e94ff1 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -6234,6 +6234,15 @@ static void get_op_vcol(oparg_T *oap, colnr_T redo_VIsual_vcol, bool initial) 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. void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) @@ -6245,11 +6254,8 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) int lbr_saved = curwin->w_p_lbr; // 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 + static redo_VIsual_T redo_VIsual = { NUL, 0, 0, 0, 0 }; + bool include_line_break = false; old_cursor = curwin->w_cursor; @@ -6332,28 +6338,27 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) 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. + // redo_VIsual.rv_line_count and redo_VIsual.rv_vcol. 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) { curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; } - VIsual_mode = redo_VIsual_mode; - if (redo_VIsual_vcol == MAXCOL || VIsual_mode == 'v') { + VIsual_mode = redo_VIsual.rv_mode; + if (redo_VIsual.rv_vcol == MAXCOL || VIsual_mode == 'v') { if (VIsual_mode == 'v') { - if (redo_VIsual_line_count <= 1) { + if (redo_VIsual.rv_line_count <= 1) { validate_virtcol(); - curwin->w_curswant = - curwin->w_virtcol + redo_VIsual_vcol - 1; + curwin->w_curswant = curwin->w_virtcol + redo_VIsual.rv_vcol - 1; } else { - curwin->w_curswant = redo_VIsual_vcol; + curwin->w_curswant = redo_VIsual.rv_vcol; } } else { curwin->w_curswant = MAXCOL; } coladvance(curwin->w_curswant); } - cap->count0 = redo_VIsual_count; + cap->count0 = redo_VIsual.rv_count; cap->count1 = (cap->count0 == 0 ? 1 : cap->count0); } else if (VIsual_active) { if (!gui_yank) { @@ -6440,7 +6445,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) virtual_op = virtual_active(); 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) { // Prepare to reselect and redo Visual: this is based on the @@ -6485,6 +6490,8 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) get_op_char(oap->op_type), get_extra_op_char(oap->op_type), oap->motion_force, cap->cmdchar, cap->nchar); } else if (cap->cmdchar != ':' && cap->cmdchar != K_COMMAND) { + int opchar = get_op_char(oap->op_type); + int extra_opchar = get_extra_op_char(oap->op_type); int nchar = oap->op_type == OP_REPLACE ? cap->nchar : NUL; // reverse what nv_replace() did @@ -6493,15 +6500,20 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) } else if (nchar == REPLACE_NL_NCHAR) { nchar = NL; } - prep_redo(oap->regname, 0L, NUL, 'v', get_op_char(oap->op_type), - get_extra_op_char(oap->op_type), nchar); + + if (opchar == 'g' && extra_opchar == '@') { + // also repeat the count for 'operatorfunc' + prep_redo_num2(oap->regname, 0L, NUL, 'v', cap->count0, opchar, extra_opchar, nchar); + } else { + prep_redo(oap->regname, 0L, NUL, 'v', opchar, extra_opchar, nchar); + } } 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; + 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; } } @@ -6751,12 +6763,20 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) op_format(oap, true); // use internal function break; - case OP_FUNCTION: + case OP_FUNCTION: { + redo_VIsual_T save_redo_VIsual = redo_VIsual; + // Restore linebreak, so that when the user edits it looks as // before. curwin->w_p_lbr = lbr_saved; - 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; + } case OP_INSERT: case OP_APPEND: @@ -6837,7 +6857,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) } else { VIsual_active = true; curwin->w_p_lbr = lbr_saved; - op_addsub(oap, (linenr_T)cap->count1, redo_VIsual_arg); + op_addsub(oap, (linenr_T)cap->count1, redo_VIsual.rv_arg); VIsual_active = false; } check_cursor_col(); diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim index 789ca747b4..82ba2cfd48 100644 --- a/src/nvim/testdir/test_normal.vim +++ b/src/nvim/testdir/test_normal.vim @@ -345,7 +345,7 @@ func Test_normal08_fold() bw! endfunc -func Test_normal09_operatorfunc() +func Test_normal09a_operatorfunc() " Test operatorfunc call Setup_NewWindow() " Add some spaces for counting @@ -375,7 +375,7 @@ func Test_normal09_operatorfunc() bw! endfunc -func Test_normal09a_operatorfunc() +func Test_normal09b_operatorfunc() " Test operatorfunc call Setup_NewWindow() " Add some spaces for counting @@ -397,10 +397,45 @@ func Test_normal09a_operatorfunc() " clean up unmap <buffer> ,, set opfunc= + call assert_fails('normal Vg@', 'E774:') bw! unlet! g:opt endfunc +func OperatorfuncRedo(_) + let g:opfunc_count = v:count +endfunc + +func Underscorize(_) + normal! '[V']r_ +endfunc + +func Test_normal09c_operatorfunc() + " Test redoing operatorfunc + new + call setline(1, 'some text') + set operatorfunc=OperatorfuncRedo + normal v3g@ + call assert_equal(3, g:opfunc_count) + let g:opfunc_count = 0 + normal . + call assert_equal(3, g:opfunc_count) + + bw! + unlet g:opfunc_count + + " Test redoing Visual mode + set operatorfunc=Underscorize + new + call setline(1, ['first', 'first', 'third', 'third', 'second']) + normal! 1GVjg@ + normal! 5G. + normal! 3G. + call assert_equal(['_____', '_____', '_____', '_____', '______'], getline(1, '$')) + bwipe! + set operatorfunc= +endfunc + func Test_normal10_expand() " Test for expand() 10new @@ -1784,9 +1819,9 @@ fun! Test_normal33_g_cmd2() %d 15vsp set wrap listchars= sbr= - let lineA='abcdefghijklmnopqrstuvwxyz' - let lineB='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' - let lineC='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' + let lineA = 'abcdefghijklmnopqrstuvwxyz' + let lineB = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' + let lineC = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' $put =lineA $put =lineB @@ -1821,6 +1856,28 @@ fun! Test_normal33_g_cmd2() call assert_equal('l', getreg(0)) call assert_beeps('normal 5g$') + " Test for g$ with double-width character half displayed + vsplit + 9wincmd | + setlocal nowrap nonumber + call setline(2, 'asdfasdfヨ') + 2 + normal 0g$ + call assert_equal(8, col('.')) + 10wincmd | + normal 0g$ + call assert_equal(9, col('.')) + + setlocal signcolumn=yes + 11wincmd | + normal 0g$ + call assert_equal(8, col('.')) + 12wincmd | + normal 0g$ + call assert_equal(9, col('.')) + + close + " Test for g_ call assert_beeps('normal! 100g_') call setline(2, [' foo ', ' foobar ']) |