changeset 26292:b79f122c6bd8 v8.2.3677

patch 8.2.3677: after a put the '] mark is on the last byte Commit: https://github.com/vim/vim/commit/4d07253a485819b3a9fd923d263e722ea2109c12 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Nov 25 19:31:15 2021 +0000 patch 8.2.3677: after a put the '] mark is on the last byte Problem: After a put the '] mark is on the last byte of a multi-byte character. Solution: Move it to the first byte. (closes #9047)
author Bram Moolenaar <Bram@vim.org>
date Thu, 25 Nov 2021 20:45:03 +0100
parents f3ace6b2bc84
children 0324433f1750
files src/register.c src/testdir/test_put.vim src/version.c
diffstat 3 files changed, 30 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/register.c
+++ b/src/register.c
@@ -2004,6 +2004,7 @@ do_put(
 	{
 	    linenr_T	end_lnum = 0; // init for gcc
 	    linenr_T	start_lnum = lnum;
+	    int		first_byte_off = 0;
 
 	    if (VIsual_active)
 	    {
@@ -2065,6 +2066,10 @@ do_put(
 		    }
 		    STRMOVE(ptr, oldp + col);
 		    ml_replace(lnum, newp, FALSE);
+
+		    // compute the byte offset for the last character
+		    first_byte_off = mb_head_off(newp, ptr - 1);
+
 		    // Place cursor on last putted char.
 		    if (lnum == curwin->w_cursor.lnum)
 		    {
@@ -2080,10 +2085,15 @@ do_put(
 		    lnum--;
 	    }
 
+	    // put '] at the first byte of the last character
 	    curbuf->b_op_end = curwin->w_cursor;
+	    curbuf->b_op_end.col -= first_byte_off;
+
 	    // For "CTRL-O p" in Insert mode, put cursor after last char
 	    if (totlen && (restart_edit != 0 || (flags & PUT_CURSEND)))
 		++curwin->w_cursor.col;
+	    else
+		curwin->w_cursor.col -= first_byte_off;
 	    changed_bytes(lnum, col);
 	}
 	else
@@ -2198,12 +2208,14 @@ error:
 		changed_lines(curbuf->b_op_start.lnum, 0,
 					   curbuf->b_op_start.lnum, nr_lines);
 
-	    // put '] mark at last inserted character
+	    // Put the '] mark on the first byte of the last inserted character.
+	    // Correct the length for change in indent.
 	    curbuf->b_op_end.lnum = new_lnum;
-	    // correct length for change in indent
 	    col = (colnr_T)STRLEN(y_array[y_size - 1]) - lendiff;
 	    if (col > 1)
-		curbuf->b_op_end.col = col - 1;
+		curbuf->b_op_end.col = col - 1
+				- mb_head_off(y_array[y_size - 1],
+						y_array[y_size - 1] + col - 1);
 	    else
 		curbuf->b_op_end.col = 0;
 
--- a/src/testdir/test_put.vim
+++ b/src/testdir/test_put.vim
@@ -197,5 +197,18 @@ func Test_put_above_first_line()
   bwipe!
 endfunc
 
+func Test_multibyte_op_end_mark()
+  new
+  call setline(1, 'ั‚ะตัั‚')
+  normal viwdp
+  call assert_equal([0, 1, 7, 0], getpos("'>"))
+  call assert_equal([0, 1, 7, 0], getpos("']"))
+
+  normal Vyp
+  call assert_equal([0, 1, 2147483647, 0], getpos("'>"))
+  call assert_equal([0, 2, 7, 0], getpos("']"))
+  bwipe!
+endfunc
+
 
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/version.c
+++ b/src/version.c
@@ -758,6 +758,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3677,
+/**/
     3676,
 /**/
     3675,