# HG changeset patch # User Bram Moolenaar # Date 1652475603 -7200 # Node ID 647d7f439622a843d2c9896de081e49803dfc3d9 # Parent e397a7fd7fc1976cae5ed72b8a10829d236f218e patch 8.2.4950: text properties position wrong after shifting text Commit: https://github.com/vim/vim/commit/4b93674159d60c985de906c30f45dbaf2b64056f Author: LemonBoy Date: Fri May 13 21:56:28 2022 +0100 patch 8.2.4950: text properties position wrong after shifting text Problem: Text properties position wrong after shifting text. Solution: Adjust the text properties when shifting a block of text. (closes #10418) diff --git a/src/ops.c b/src/ops.c --- 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; - - newp = alloc(new_line_len); + + (unsigned)STRLEN(non_white); + + 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 diff --git a/src/testdir/test_textprop.vim b/src/testdir/test_textprop.vim --- a/src/testdir/test_textprop.vim +++ b/src/testdir/test_textprop.vim @@ -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\>", 'nxt') + call cursor(2, 1) + call feedkeys("5l\<", '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 diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -747,6 +747,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 4950, +/**/ 4949, /**/ 4948,