# HG changeset patch # User Bram Moolenaar # Date 1623347102 -7200 # Node ID f1121eb17e143abf31b2972a5f0d32fb9d03f6b2 # Parent 8dfff43cdcb8e276b88aff4658205a0fd3e27bd5 patch 8.2.2971: cannot yank a block without trailing spaces Commit: https://github.com/vim/vim/commit/544a38e44db0f25ec4fa7a2a4666cf28a2336f33 Author: Christian Brabandt Date: Thu Jun 10 19:39:11 2021 +0200 patch 8.2.2971: cannot yank a block without trailing spaces Problem: Cannot yank a block without trailing spaces. Solution: Add the "zy" command. (Christian Brabandt, closes https://github.com/vim/vim/issues/8292) diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -1042,6 +1042,10 @@ 5. Copying and moving text *copy-move cursor to the end of line (which is more logical, but not Vi-compatible) use ":map Y y$". + *zy* +["x]zy{motion} Yank {motion} text [into register x]. Only differs + from `y` when selecting a block of text, see |v_zy|. + *v_y* {Visual}["x]y Yank the highlighted text [into register x] (for {Visual} see |Visual-mode|). @@ -1050,6 +1054,12 @@ 5. Copying and moving text *copy-move {Visual}["x]Y Yank the highlighted lines [into register x] (for {Visual} see |Visual-mode|). + *v_zy* +{Visual}["x]zy Yank the highlighted text [into register x]. Trailing + whitespace at the end of each line of a selected block + won't be yanked. Especially useful in combination + with `zp`. (for {Visual} see |Visual-mode|) + *:y* *:yank* *E850* :[range]y[ank] [x] Yank [range] lines [into register x]. Yanking to the "* or "+ registers is possible only when the @@ -1129,7 +1139,8 @@ 5. Copying and moving text *copy-move ["x]zp or *zp* *zP* ["x]zP Like "p" and "P", except without adding trailing spaces when pasting a block. Thus the inserted text will not - always be a rectangle. + always be a rectangle. Especially useful in + combination with |v_zy|. You can use these commands to copy text from one place to another. Do this by first getting the text into a register with a yank, delete or change diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -878,6 +878,7 @@ tag char note action in Normal mo |zv| zv open enough folds to view the cursor line |zw| zw permanently mark word as incorrectly spelled |zx| zx re-apply 'foldlevel' and do "zv" +|zy| zy yank without trailing spaces |zz| zz redraw, cursor line at center of window |z| z same as "zh" |z| z same as "zl" diff --git a/src/normal.c b/src/normal.c --- a/src/normal.c +++ b/src/normal.c @@ -2985,6 +2985,9 @@ dozet: case 'P': case 'p': nv_put(cap); break; + // "zy" Yank without trailing spaces + case 'y': nv_operator(cap); + break; #ifdef FEAT_FOLDING // "zF": create fold command // "zf": create fold operator diff --git a/src/ops.c b/src/ops.c --- a/src/ops.c +++ b/src/ops.c @@ -78,6 +78,8 @@ get_op_type(int char1, int char2) return OP_NR_ADD; if (char1 == 'g' && char2 == Ctrl_X) // subtract return OP_NR_SUB; + if (char1 == 'z' && char2 == 'y') // OP_YANK + return OP_YANK; for (i = 0; ; ++i) { if (opchars[i][0] == char1 && opchars[i][1] == char2) @@ -3894,6 +3896,7 @@ do_pending_operator(cmdarg_T *cap, int o #ifdef FEAT_LINEBREAK curwin->w_p_lbr = lbr_saved; #endif + oap->excl_tr_ws = cap->cmdchar == 'z'; (void)op_yank(oap, FALSE, !gui_yank); } check_cursor_col(); diff --git a/src/register.c b/src/register.c --- a/src/register.c +++ b/src/register.c @@ -32,7 +32,7 @@ static int stuff_yank(int, char_u *); static void put_reedit_in_typebuf(int silent); static int put_in_typebuf(char_u *s, int esc, int colon, int silent); -static int yank_copy_line(struct block_def *bd, long y_idx); +static int yank_copy_line(struct block_def *bd, long y_idx, int exclude_trailing_space); #ifdef FEAT_CLIPBOARD static void copy_yank_reg(yankreg_T *reg); #endif @@ -1208,20 +1208,20 @@ op_yank(oparg_T *oap, int deleting, int { case MBLOCK: block_prep(oap, &bd, lnum, FALSE); - if (yank_copy_line(&bd, y_idx) == FAIL) + if (yank_copy_line(&bd, y_idx, oap->excl_tr_ws) == FAIL) goto fail; break; case MLINE: if ((y_current->y_array[y_idx] = - vim_strsave(ml_get(lnum))) == NULL) + vim_strsave(ml_get(lnum))) == NULL) goto fail; break; case MCHAR: { colnr_T startcol = 0, endcol = MAXCOL; - int is_oneChar = FALSE; + int is_oneChar = FALSE; colnr_T cs, ce; p = ml_get(lnum); @@ -1282,7 +1282,7 @@ op_yank(oparg_T *oap, int deleting, int else bd.textlen = endcol - startcol + oap->inclusive; bd.textstart = p + startcol; - if (yank_copy_line(&bd, y_idx) == FAIL) + if (yank_copy_line(&bd, y_idx, FALSE) == FAIL) goto fail; break; } @@ -1443,8 +1443,12 @@ fail: // free the allocated lines return FAIL; } +/* + * Copy a block range into a register. + * If "exclude_trailing_space" is set, do not copy trailing whitespaces. + */ static int -yank_copy_line(struct block_def *bd, long y_idx) +yank_copy_line(struct block_def *bd, long y_idx, int exclude_trailing_space) { char_u *pnew; @@ -1458,6 +1462,16 @@ yank_copy_line(struct block_def *bd, lon pnew += bd->textlen; vim_memset(pnew, ' ', (size_t)bd->endspaces); pnew += bd->endspaces; + if (exclude_trailing_space) + { + int s = bd->textlen + bd->endspaces; + + while (VIM_ISWHITE(*(bd->textstart + s - 1)) && s > 0) + { + s = s - (*mb_head_off)(bd->textstart, bd->textstart + s - 1) - 1; + pnew--; + } + } *pnew = NUL; return OK; } diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -3772,7 +3772,7 @@ typedef struct oparg_S int use_reg_one; // TRUE if delete uses reg 1 even when not // linewise int inclusive; // TRUE if char motion is inclusive (only - // valid when motion_type is MCHAR + // valid when motion_type is MCHAR) int end_adjusted; // backuped b_op_end one char (only used by // do_format()) pos_T start; // start of the operator @@ -3789,6 +3789,8 @@ typedef struct oparg_S colnr_T end_vcol; // end col for block mode operator long prev_opcount; // ca.opcount saved for K_CURSORHOLD long prev_count0; // ca.count0 saved for K_CURSORHOLD + int excl_tr_ws; // exclude trailing whitespace for yank of a + // block } oparg_T; /* diff --git a/src/testdir/test_visual.vim b/src/testdir/test_visual.vim --- a/src/testdir/test_visual.vim +++ b/src/testdir/test_visual.vim @@ -1171,4 +1171,59 @@ func Test_visual_put_in_block_using_zp() bwipe! endfunc +func Test_visual_put_in_block_using_zy_and_zp() + new + + " Test 1) Paste using zp - after the cursor without trailing spaces + call setline(1, ['/path;text', '/path;text', '/path;text', '', + \ 'texttext /subdir columntext', + \ 'texttext /longsubdir columntext', + \ 'texttext /longlongsubdir columntext']) + exe "normal! 5G0f/\2jezy" + norm! 1G0f;hzp + call assert_equal(['/path/subdir;text', '/path/longsubdir;text', '/path/longlongsubdir;text'], getline(1, 3)) + + " Test 2) Paste using zP - in front of the cursor without trailing spaces + %d + call setline(1, ['/path;text', '/path;text', '/path;text', '', + \ 'texttext /subdir columntext', + \ 'texttext /longsubdir columntext', + \ 'texttext /longlongsubdir columntext']) + exe "normal! 5G0f/\2jezy" + norm! 1G0f;zP + call assert_equal(['/path/subdir;text', '/path/longsubdir;text', '/path/longlongsubdir;text'], getline(1, 3)) + + " Test 3) Paste using p - with trailing spaces + %d + call setline(1, ['/path;text', '/path;text', '/path;text', '', + \ 'texttext /subdir columntext', + \ 'texttext /longsubdir columntext', + \ 'texttext /longlongsubdir columntext']) + exe "normal! 5G0f/\2jezy" + norm! 1G0f;hp + call assert_equal(['/path/subdir ;text', '/path/longsubdir ;text', '/path/longlongsubdir;text'], getline(1, 3)) + + " Test 4) Paste using P - with trailing spaces + %d + call setline(1, ['/path;text', '/path;text', '/path;text', '', + \ 'texttext /subdir columntext', + \ 'texttext /longsubdir columntext', + \ 'texttext /longlongsubdir columntext']) + exe "normal! 5G0f/\2jezy" + norm! 1G0f;P + call assert_equal(['/path/subdir ;text', '/path/longsubdir ;text', '/path/longlongsubdir;text'], getline(1, 3)) + + " Test 5) Yank with spaces inside the block + %d + call setline(1, ['/path;text', '/path;text', '/path;text', '', + \ 'texttext /sub dir/ columntext', + \ 'texttext /lon gsubdir/ columntext', + \ 'texttext /lon glongsubdir/ columntext']) + exe "normal! 5G0f/\2jf/zy" + norm! 1G0f;zP + call assert_equal(['/path/sub dir/;text', '/path/lon gsubdir/;text', '/path/lon glongsubdir/;text'], getline(1, 3)) + 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 @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2971, +/**/ 2970, /**/ 2969,