0
0
mirror of https://github.com/vim/vim.git synced 2025-08-25 19:53:53 -04:00

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 #8292)
This commit is contained in:
Christian Brabandt 2021-06-10 19:39:11 +02:00 committed by Bram Moolenaar
parent 31e299c08f
commit 544a38e44d
8 changed files with 99 additions and 8 deletions

View File

@ -1042,6 +1042,10 @@ inside of strings can change! Also see 'softtabstop' option. >
cursor to the end of line (which is more logical, cursor to the end of line (which is more logical,
but not Vi-compatible) use ":map Y y$". 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* *v_y*
{Visual}["x]y Yank the highlighted text [into register x] (for {Visual}["x]y Yank the highlighted text [into register x] (for
{Visual} see |Visual-mode|). {Visual} see |Visual-mode|).
@ -1050,6 +1054,12 @@ inside of strings can change! Also see 'softtabstop' option. >
{Visual}["x]Y Yank the highlighted lines [into register x] (for {Visual}["x]Y Yank the highlighted lines [into register x] (for
{Visual} see |Visual-mode|). {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* *:y* *:yank* *E850*
:[range]y[ank] [x] Yank [range] lines [into register x]. Yanking to the :[range]y[ank] [x] Yank [range] lines [into register x]. Yanking to the
"* or "+ registers is possible only when the "* or "+ registers is possible only when the
@ -1129,7 +1139,8 @@ inside of strings can change! Also see 'softtabstop' option. >
["x]zp or *zp* *zP* ["x]zp or *zp* *zP*
["x]zP Like "p" and "P", except without adding trailing spaces ["x]zP Like "p" and "P", except without adding trailing spaces
when pasting a block. Thus the inserted text will not 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 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 by first getting the text into a register with a yank, delete or change

View File

@ -878,6 +878,7 @@ tag char note action in Normal mode ~
|zv| zv open enough folds to view the cursor line |zv| zv open enough folds to view the cursor line
|zw| zw permanently mark word as incorrectly spelled |zw| zw permanently mark word as incorrectly spelled
|zx| zx re-apply 'foldlevel' and do "zv" |zx| zx re-apply 'foldlevel' and do "zv"
|zy| zy yank without trailing spaces
|zz| zz redraw, cursor line at center of window |zz| zz redraw, cursor line at center of window
|z<Left>| z<Left> same as "zh" |z<Left>| z<Left> same as "zh"
|z<Right>| z<Right> same as "zl" |z<Right>| z<Right> same as "zl"

View File

@ -2985,6 +2985,9 @@ dozet:
case 'P': case 'P':
case 'p': nv_put(cap); case 'p': nv_put(cap);
break; break;
// "zy" Yank without trailing spaces
case 'y': nv_operator(cap);
break;
#ifdef FEAT_FOLDING #ifdef FEAT_FOLDING
// "zF": create fold command // "zF": create fold command
// "zf": create fold operator // "zf": create fold operator

View File

@ -78,6 +78,8 @@ get_op_type(int char1, int char2)
return OP_NR_ADD; return OP_NR_ADD;
if (char1 == 'g' && char2 == Ctrl_X) // subtract if (char1 == 'g' && char2 == Ctrl_X) // subtract
return OP_NR_SUB; return OP_NR_SUB;
if (char1 == 'z' && char2 == 'y') // OP_YANK
return OP_YANK;
for (i = 0; ; ++i) for (i = 0; ; ++i)
{ {
if (opchars[i][0] == char1 && opchars[i][1] == char2) if (opchars[i][0] == char1 && opchars[i][1] == char2)
@ -3894,6 +3896,7 @@ do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank)
#ifdef FEAT_LINEBREAK #ifdef FEAT_LINEBREAK
curwin->w_p_lbr = lbr_saved; curwin->w_p_lbr = lbr_saved;
#endif #endif
oap->excl_tr_ws = cap->cmdchar == 'z';
(void)op_yank(oap, FALSE, !gui_yank); (void)op_yank(oap, FALSE, !gui_yank);
} }
check_cursor_col(); check_cursor_col();

View File

@ -32,7 +32,7 @@ static int stuff_yank(int, char_u *);
static void put_reedit_in_typebuf(int silent); static void put_reedit_in_typebuf(int silent);
static int put_in_typebuf(char_u *s, int esc, int colon, static int put_in_typebuf(char_u *s, int esc, int colon,
int silent); 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 #ifdef FEAT_CLIPBOARD
static void copy_yank_reg(yankreg_T *reg); static void copy_yank_reg(yankreg_T *reg);
#endif #endif
@ -1208,20 +1208,20 @@ op_yank(oparg_T *oap, int deleting, int mess)
{ {
case MBLOCK: case MBLOCK:
block_prep(oap, &bd, lnum, FALSE); 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; goto fail;
break; break;
case MLINE: case MLINE:
if ((y_current->y_array[y_idx] = if ((y_current->y_array[y_idx] =
vim_strsave(ml_get(lnum))) == NULL) vim_strsave(ml_get(lnum))) == NULL)
goto fail; goto fail;
break; break;
case MCHAR: case MCHAR:
{ {
colnr_T startcol = 0, endcol = MAXCOL; colnr_T startcol = 0, endcol = MAXCOL;
int is_oneChar = FALSE; int is_oneChar = FALSE;
colnr_T cs, ce; colnr_T cs, ce;
p = ml_get(lnum); p = ml_get(lnum);
@ -1282,7 +1282,7 @@ op_yank(oparg_T *oap, int deleting, int mess)
else else
bd.textlen = endcol - startcol + oap->inclusive; bd.textlen = endcol - startcol + oap->inclusive;
bd.textstart = p + startcol; bd.textstart = p + startcol;
if (yank_copy_line(&bd, y_idx) == FAIL) if (yank_copy_line(&bd, y_idx, FALSE) == FAIL)
goto fail; goto fail;
break; break;
} }
@ -1443,8 +1443,12 @@ fail: // free the allocated lines
return FAIL; return FAIL;
} }
/*
* Copy a block range into a register.
* If "exclude_trailing_space" is set, do not copy trailing whitespaces.
*/
static int 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; char_u *pnew;
@ -1458,6 +1462,16 @@ yank_copy_line(struct block_def *bd, long y_idx)
pnew += bd->textlen; pnew += bd->textlen;
vim_memset(pnew, ' ', (size_t)bd->endspaces); vim_memset(pnew, ' ', (size_t)bd->endspaces);
pnew += 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; *pnew = NUL;
return OK; return OK;
} }

View File

@ -3772,7 +3772,7 @@ typedef struct oparg_S
int use_reg_one; // TRUE if delete uses reg 1 even when not int use_reg_one; // TRUE if delete uses reg 1 even when not
// linewise // linewise
int inclusive; // TRUE if char motion is inclusive (only 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 int end_adjusted; // backuped b_op_end one char (only used by
// do_format()) // do_format())
pos_T start; // start of the operator 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 colnr_T end_vcol; // end col for block mode operator
long prev_opcount; // ca.opcount saved for K_CURSORHOLD long prev_opcount; // ca.opcount saved for K_CURSORHOLD
long prev_count0; // ca.count0 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; } oparg_T;
/* /*

View File

@ -1171,4 +1171,59 @@ func Test_visual_put_in_block_using_zp()
bwipe! bwipe!
endfunc 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/\<c-v>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/\<c-v>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/\<c-v>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/\<c-v>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/\<c-v>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 " vim: shiftwidth=2 sts=2 expandtab

View File

@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
2971,
/**/ /**/
2970, 2970,
/**/ /**/