From d9cb3fba9228aed5109a8e6069c50e4f265be9f3 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 9 Feb 2022 14:21:04 +0800 Subject: [PATCH 1/3] vim-patch:8.2.4242: put in Visual mode cannot be repeated Problem: Put in Visual mode cannot be repeated. Solution: Use "P" to put without yanking the deleted text into the unnamed register. (Shougo Matsushita, closes vim/vim#9591) https://github.com/vim/vim/commit/fb55207ed17918c8a2a6cadf5ad9d5fcf686a7ab Cherry-pick get_y_previous() and set_y_previous() from patch 8.1.1736. Nvim has removed y_current, so code related to it is N/A. --- runtime/doc/visual.txt | 1 + src/nvim/normal.c | 12 ++++++++++-- src/nvim/ops.c | 16 ++++++++++++---- src/nvim/testdir/test_visual.vim | 24 ++++++++++++++++++++++++ test/functional/editor/put_spec.lua | 12 +++++++++--- 5 files changed, 56 insertions(+), 9 deletions(-) diff --git a/runtime/doc/visual.txt b/runtime/doc/visual.txt index 5563a56216..4d5366a41a 100644 --- a/runtime/doc/visual.txt +++ b/runtime/doc/visual.txt @@ -255,6 +255,7 @@ Additionally the following commands can be used: X delete (2) |v_X| Y yank (2) |v_Y| p put |v_p| + P put without unnamed register overwrite |v_P| J join (1) |v_J| U make uppercase |v_U| u make lowercase |v_u| diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 225c66aae1..21c465434a 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -7509,9 +7509,9 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent) // overwrites if the old contents is being put. was_visual = true; regname = cap->oap->regname; + bool save_unnamed = cap->cmdchar == 'P'; // '+' and '*' could be the same selection - bool clipoverwrite = (regname == '+' || regname == '*') - && (cb_flags & CB_UNNAMEDMASK); + bool clipoverwrite = (regname == '+' || regname == '*') && (cb_flags & CB_UNNAMEDMASK); if (regname == 0 || regname == '"' || clipoverwrite || ascii_isdigit(regname) || regname == '-') { // The delete might overwrite the register we want to put, save it first @@ -7524,6 +7524,10 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent) // do_put(), which requires the visual selection to still be active. if (!VIsual_active || VIsual_mode == 'V' || regname != '.') { // Now delete the selected text. Avoid messages here. + yankreg_T *old_y_previous; + if (save_unnamed) { + old_y_previous = get_y_previous(); + } cap->cmdchar = 'd'; cap->nchar = NUL; cap->oap->regname = NUL; @@ -7533,6 +7537,10 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent) empty = (curbuf->b_ml.ml_flags & ML_EMPTY); msg_silent--; + if (save_unnamed) { + set_y_previous(old_y_previous); + } + // delete PUT_LINE_BACKWARD; cap->oap->regname = regname; } diff --git a/src/nvim/ops.c b/src/nvim/ops.c index b8b639265c..f8ab6b2556 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -135,10 +135,18 @@ static char opchars[][3] = { Ctrl_X, NUL, OPF_CHANGE }, // OP_NR_SUB }; -/* - * Translate a command name into an operator type. - * Must only be called with a valid operator name! - */ +yankreg_T *get_y_previous(void) +{ + return y_previous; +} + +void set_y_previous(yankreg_T *yreg) +{ + y_previous = yreg; +} + +/// Translate a command name into an operator type. +/// Must only be called with a valid operator name! int get_op_type(int char1, int char2) { int i; diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim index 76274fb038..e931e06175 100644 --- a/src/nvim/testdir/test_visual.vim +++ b/src/nvim/testdir/test_visual.vim @@ -1184,8 +1184,32 @@ func Test_visual_undo_deletes_last_line() exe "normal ggvjfxO" undo normal gNU + bwipe! endfunc +func Test_visual_paste() + new + + " v_p overwrites unnamed register. + call setline(1, ['xxxx']) + call setreg('"', 'foo') + call setreg('-', 'bar') + normal 1Gvp + call assert_equal(@", 'x') + call assert_equal(@-, 'x') + + if has('clipboard') + " v_P does not overwrite unnamed register. + call setline(1, ['xxxx']) + call setreg('"', 'foo') + call setreg('-', 'bar') + normal 1GvP + call assert_equal(@", 'foo') + call assert_equal(@-, 'x') + endif + + bwipe! +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/functional/editor/put_spec.lua b/test/functional/editor/put_spec.lua index fdda2be131..c367f8fdd0 100644 --- a/test/functional/editor/put_spec.lua +++ b/test/functional/editor/put_spec.lua @@ -507,7 +507,9 @@ describe('put command', function() return function(exception_table, after_redo) test_expect(exception_table, after_redo) if selection_string then - eq(selection_string, getreg('"')) + if not conversion_table.put_backwards then + eq(selection_string, getreg('"')) + end else eq('test_string"', getreg('"')) end @@ -714,7 +716,9 @@ describe('put command', function() expect_base, conversion_table) return function(exception_table, after_redo) test_expect(exception_table, after_redo) - eq('Line of words 1\n', getreg('"')) + if not conversion_table.put_backwards then + eq('Line of words 1\n', getreg('"')) + end end end local base_expect_string = [[ @@ -748,7 +752,9 @@ describe('put command', function() end, expect_base, conversion_table) return function(e,c) test_expect(e,c) - eq('Lin\nLin', getreg('"')) + if not conversion_table.put_backwards then + eq('Lin\nLin', getreg('"')) + end end end From 196160b1838a462a819bcecb5921b96c2089cb20 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 9 Feb 2022 14:21:04 +0800 Subject: [PATCH 2/3] vim-patch:partial:f10911e5db16 Update runtime files https://github.com/vim/vim/commit/f10911e5db16f1fe6ab519c5d091ad0c1df0d063 --- runtime/doc/change.txt | 7 +++++-- runtime/doc/index.txt | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index e26a84f80f..b4d3304880 100644 --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -1118,8 +1118,11 @@ register. With blockwise selection it also depends on the size of the block and whether the corners are on an existing character. (Implementation detail: it actually works by first putting the register after the selection and then deleting the selection.) -The previously selected text is put in the unnamed register. If you want to -put the same text into a Visual selection several times you need to use +With 'p' the previously selected text is put in the unnamed register. This is +useful if you want to put that text somewhere else. But you cannot repeat the +same change. +With 'P' the unnamed register is not changed, you can repeat the same change. +But the deleted text cannot be used. If you do need it you can use 'p' with another register. E.g., yank the text to copy, Visually select the text to replace and use "0p . You can repeat this as many times as you like, and the unnamed register will be changed each time. diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index f02f9f8032..e3bc3d5437 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -923,7 +923,9 @@ tag command note action in Visual mode ~ before the highlighted area |v_J| J 2 join the highlighted lines |v_K| K run 'keywordprg' on the highlighted area -|v_O| O move horizontally to other corner of area. +|v_O| O move horizontally to other corner of area +|v_P| P replace highlighted area with register + contents; unnamed register is unchanged Q does not start Ex mode |v_R| R 2 delete the highlighted lines and start insert From 3fe47647c7b902d882d3d72158f2712490506a75 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 9 Feb 2022 14:21:04 +0800 Subject: [PATCH 3/3] vim-patch:8.2.4315: put in Visual mode not fully tested Problem: Put in Visual mode not fully tested. Solution: Add a few more test cases. (closes vim/vim#9708) https://github.com/vim/vim/commit/6bf821e8abe1da24e5d0624f032d7eda745756e8 --- src/nvim/testdir/test_visual.vim | 46 +++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim index e931e06175..099a90643f 100644 --- a/src/nvim/testdir/test_visual.vim +++ b/src/nvim/testdir/test_visual.vim @@ -1195,18 +1195,52 @@ func Test_visual_paste() call setline(1, ['xxxx']) call setreg('"', 'foo') call setreg('-', 'bar') - normal 1Gvp - call assert_equal(@", 'x') - call assert_equal(@-, 'x') + normal gg0vp + call assert_equal('x', @") + call assert_equal('x', @-) + call assert_equal('fooxxx', getline(1)) + normal $vp + call assert_equal('x', @") + call assert_equal('x', @-) + call assert_equal('fooxxx', getline(1)) + " Test with a different register as unnamed register. + call setline(2, ['baz']) + normal 2gg0"rD + call assert_equal('baz', @") + normal gg0vp + call assert_equal('f', @") + call assert_equal('f', @-) + call assert_equal('bazooxxx', getline(1)) + normal $vp + call assert_equal('x', @") + call assert_equal('x', @-) + call assert_equal('bazooxxf', getline(1)) if has('clipboard') " v_P does not overwrite unnamed register. call setline(1, ['xxxx']) call setreg('"', 'foo') call setreg('-', 'bar') - normal 1GvP - call assert_equal(@", 'foo') - call assert_equal(@-, 'x') + normal gg0vP + call assert_equal('foo', @") + call assert_equal('x', @-) + call assert_equal('fooxxx', getline(1)) + normal $vP + call assert_equal('foo', @") + call assert_equal('x', @-) + call assert_equal('fooxxfoo', getline(1)) + " Test with a different register as unnamed register. + call setline(2, ['baz']) + normal 2gg0"rD + call assert_equal('baz', @") + normal gg0vP + call assert_equal('baz', @") + call assert_equal('f', @-) + call assert_equal('bazooxxfoo', getline(1)) + normal $vP + call assert_equal('baz', @") + call assert_equal('o', @-) + call assert_equal('bazooxxfobaz', getline(1)) endif bwipe!