]> granicus.if.org Git - vim/commitdiff
patch 8.2.4950: text properties position wrong after shifting text v8.2.4950
authorLemonBoy <thatlemon@gmail.com>
Fri, 13 May 2022 20:56:28 +0000 (21:56 +0100)
committerBram Moolenaar <Bram@vim.org>
Fri, 13 May 2022 20:56:28 +0000 (21:56 +0100)
Problem:    Text properties position wrong after shifting text.
Solution:   Adjust the text properties when shifting a block of text.
            (closes #10418)

src/ops.c
src/testdir/test_textprop.vim
src/version.c

index 3940e484ce083ce096caad6d1998d8f7935a819d..4adeb09453bdb53c7f4519d164b553c6890a6e66 100644 (file)
--- a/src/ops.c
+++ b/src/ops.c
@@ -286,8 +286,9 @@ shift_block(oparg_T *oap, int amount)
     struct block_def   bd;
     int                        incr;
     colnr_T            ws_vcol;
-    int                        i = 0, j = 0;
-    int                        len;
+    int                        added;
+    unsigned           new_line_len;   // the length of the line after the
+                                       // block shift
 #ifdef FEAT_RIGHTLEFT
     int                        old_p_ri = p_ri;
 
@@ -308,6 +309,8 @@ shift_block(oparg_T *oap, int amount)
 
     if (!left)
     {
+       int     tabs = 0, spaces = 0;
+
        /*
         *  1. Get start vcol
         *  2. Total ws vcols
@@ -343,29 +346,29 @@ shift_block(oparg_T *oap, int amount)
 #ifdef FEAT_VARTABS
        if (!curbuf->b_p_et)
            tabstop_fromto(ws_vcol, ws_vcol + total,
-                                       ts_val, curbuf->b_p_vts_array, &i, &j);
+                               ts_val, curbuf->b_p_vts_array, &tabs, &spaces);
        else
-           j = total;
+           spaces = total;
 #else
        if (!curbuf->b_p_et)
-           i = ((ws_vcol % ts_val) + total) / ts_val; // number of tabs
-       if (i)
-           j = ((ws_vcol % ts_val) + total) % ts_val; // number of spp
+           tabs = ((ws_vcol % ts_val) + total) / ts_val; // number of tabs
+       if (tabs > 0)
+           spaces = ((ws_vcol % ts_val) + total) % ts_val; // number of spp
        else
-           j = total;
+           spaces = total;
 #endif
        // if we're splitting a TAB, allow for it
        bd.textcol -= bd.pre_whitesp_c - (bd.startspaces != 0);
-       len = (int)STRLEN(bd.textstart) + 1;
-       newp = alloc(bd.textcol + i + j + len);
+
+       new_line_len = bd.textcol + tabs + spaces + (int)STRLEN(bd.textstart);
+       newp = alloc(new_line_len + 1);
        if (newp == NULL)
            return;
-       vim_memset(newp, NUL, (size_t)(bd.textcol + i + j + len));
        mch_memmove(newp, oldp, (size_t)bd.textcol);
-       vim_memset(newp + bd.textcol, TAB, (size_t)i);
-       vim_memset(newp + bd.textcol + i, ' ', (size_t)j);
-       // the end
-       mch_memmove(newp + bd.textcol + i + j, bd.textstart, (size_t)len);
+       vim_memset(newp + bd.textcol, TAB, (size_t)tabs);
+       vim_memset(newp + bd.textcol + tabs, ' ', (size_t)spaces);
+       // Note that STRMOVE() copies the trailing NUL.
+       STRMOVE(newp + bd.textcol + tabs + spaces, bd.textstart);
     }
     else // left
     {
@@ -376,8 +379,6 @@ shift_block(oparg_T *oap, int amount)
        colnr_T     verbatim_copy_width;// the (displayed) width of this part
                                        // of line
        unsigned    fill;               // nr of spaces that replace a TAB
-       unsigned    new_line_len;       // the length of the line after the
-                                       // block shift
        size_t      block_space_width;
        size_t      shift_amount;
        char_u      *non_white = bd.textstart;
@@ -448,18 +449,20 @@ shift_block(oparg_T *oap, int amount)
        // - the rest of the line, pointed to by non_white.
        new_line_len = (unsigned)(verbatim_copy_end - oldp)
                       + fill
-                      + (unsigned)STRLEN(non_white) + 1;
+                      + (unsigned)STRLEN(non_white);
 
-       newp = alloc(new_line_len);
+       newp = alloc(new_line_len + 1);
        if (newp == NULL)
            return;
        mch_memmove(newp, oldp, (size_t)(verbatim_copy_end - oldp));
        vim_memset(newp + (verbatim_copy_end - oldp), ' ', (size_t)fill);
+       // Note that STRMOVE() copies the trailing NUL.
        STRMOVE(newp + (verbatim_copy_end - oldp) + fill, non_white);
     }
     // replace the line
+    added = new_line_len - (int)STRLEN(oldp);
     ml_replace(curwin->w_cursor.lnum, newp, FALSE);
-    changed_bytes(curwin->w_cursor.lnum, bd.textcol);
+    inserted_bytes(curwin->w_cursor.lnum, bd.textcol, added);
     State = oldstate;
     curwin->w_cursor.col = oldcol;
 #ifdef FEAT_RIGHTLEFT
index 20ab85a8cc91c0caf284093cb1ccf2792aeba073..e2988664b9ade0e103ad0c93181456ce2e657aea 100644 (file)
@@ -1933,5 +1933,29 @@ func Test_prop_spell()
   bwipe!
 endfunc
 
+func Test_prop_shift_block()
+  new
+  call AddPropTypes()
+
+  call setline(1, ['some     highlighted text']->repeat(2))
+  call prop_add(1, 10, #{type: 'one', length: 11})
+  call prop_add(2, 10, #{type: 'two', length: 11})
+
+  call cursor(1, 1)
+  call feedkeys("5l\<c-v>>", 'nxt')
+  call cursor(2, 1)
+  call feedkeys("5l\<c-v><", 'nxt')
+
+  let expected = [
+      \ {'lnum': 1, 'id': 0, 'col': 8, 'type_bufnr': 0, 'end': 1, 'type': 'one',
+      \ 'length': 11, 'start' : 1},
+      \ {'lnum': 2, 'id': 0, 'col': 6, 'type_bufnr': 0, 'end': 1, 'type': 'two',
+      \ 'length': 11, 'start' : 1}
+      \ ]
+  call assert_equal(expected, prop_list(1, #{end_lnum: 2}))
+
+  call DeletePropTypes()
+  bwipe!
+endfunc
 
 " vim: shiftwidth=2 sts=2 expandtab
index d2cc3225d3bf47a523a29ec0d046198851069070..8d3f2e76f15d6fb2dd2fa60203d40ed477ab40a0 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4950,
 /**/
     4949,
 /**/