1
0
forked from aniani/vim

patch 9.1.0443: Can't use blockwise selection with width for getregion()

Problem:  Can't use a blockwise selection with a width for getregion().
Solution: Add support for blockwise selection with width like the return
          value of getregtype() or the "regtype" value of TextYankPost
          (zeertzjq).

closes: #14842

Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
zeertzjq
2024-05-24 19:07:12 +02:00
committed by Christian Brabandt
parent 5e45715084
commit afc2295c22
4 changed files with 92 additions and 36 deletions

View File

@@ -4288,14 +4288,13 @@ getregion({pos1}, {pos2} [, {opts}]) *getregion()*
The optional argument {opts} is a Dict and supports the The optional argument {opts} is a Dict and supports the
following items: following items:
type Specify the region's selection type type Specify the region's selection type.
(default: "v"): See |getregtype()| for possible values,
"v" for |characterwise| mode except it cannot be an empty string.
"V" for |linewise| mode (default: "v")
"<CTRL-V>" for |blockwise-visual| mode
exclusive If |TRUE|, use exclusive selection exclusive If |TRUE|, use exclusive selection
for the end position for the end position.
(default: follow 'selection') (default: follow 'selection')
You can get the last selection type by |visualmode()|. You can get the last selection type by |visualmode()|.

View File

@@ -5492,12 +5492,13 @@ getregionpos(
pos_T *p2, pos_T *p2,
int *inclusive, int *inclusive,
int *region_type, int *region_type,
oparg_T *oa) oparg_T *oap)
{ {
int fnum1 = -1, fnum2 = -1; int fnum1 = -1, fnum2 = -1;
char_u *type; char_u *type;
buf_T *findbuf; buf_T *findbuf;
char_u default_type[] = "v"; char_u default_type[] = "v";
int block_width = 0;
int is_select_exclusive; int is_select_exclusive;
int l; int l;
@@ -5533,8 +5534,17 @@ getregionpos(
*region_type = MCHAR; *region_type = MCHAR;
else if (type[0] == 'V' && type[1] == NUL) else if (type[0] == 'V' && type[1] == NUL)
*region_type = MLINE; *region_type = MLINE;
else if (type[0] == Ctrl_V && type[1] == NUL) else if (type[0] == Ctrl_V)
{
char_u *p = type + 1;
if (*p != NUL && ((block_width = getdigits(&p)) <= 0 || *p != NUL))
{
semsg(_(e_invalid_value_for_argument_str_str), "type", type);
return FAIL;
}
*region_type = MBLOCK; *region_type = MBLOCK;
}
else else
{ {
semsg(_(e_invalid_value_for_argument_str_str), "type", type); semsg(_(e_invalid_value_for_argument_str_str), "type", type);
@@ -5608,16 +5618,18 @@ getregionpos(
getvvcol(curwin, p1, &sc1, NULL, &ec1); getvvcol(curwin, p1, &sc1, NULL, &ec1);
getvvcol(curwin, p2, &sc2, NULL, &ec2); getvvcol(curwin, p2, &sc2, NULL, &ec2);
oa->motion_type = MBLOCK; oap->motion_type = MBLOCK;
oa->inclusive = TRUE; oap->inclusive = TRUE;
oa->op_type = OP_NOP; oap->op_type = OP_NOP;
oa->start = *p1; oap->start = *p1;
oa->end = *p2; oap->end = *p2;
oa->start_vcol = MIN(sc1, sc2); oap->start_vcol = MIN(sc1, sc2);
if (is_select_exclusive && ec1 < sc2 && 0 < sc2 && ec2 > ec1) if (block_width > 0)
oa->end_vcol = sc2 - 1; oap->end_vcol = oap->start_vcol + block_width - 1;
else if (is_select_exclusive && ec1 < sc2 && 0 < sc2 && ec2 > ec1)
oap->end_vcol = sc2 - 1;
else else
oa->end_vcol = MAX(ec1, ec2); oap->end_vcol = MAX(ec1, ec2);
} }
// Include the trailing byte of a multi-byte char. // Include the trailing byte of a multi-byte char.

View File

@@ -1964,6 +1964,14 @@ func Test_visual_getregion()
#" using invalid value for "type" #" using invalid value for "type"
call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': '' })", 'E475:') call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': '' })", 'E475:')
call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': '' })", 'E475:') call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': '' })", 'E475:')
call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': 'v0' })", 'E475:')
call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': 'v0' })", 'E475:')
call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': 'V0' })", 'E475:')
call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': 'V0' })", 'E475:')
call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': '\<C-v>0' })", 'E475:')
call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': '\<C-v>0' })", 'E475:')
call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': '\<C-v>1:' })", 'E475:')
call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': '\<C-v>1:' })", 'E475:')
#" using a mark from another buffer to current buffer #" using a mark from another buffer to current buffer
new new
@@ -2542,30 +2550,65 @@ func Test_getregion_invalid_buf()
bwipe! bwipe!
endfunc endfunc
func Test_getregion_maxcol() func Test_getregion_after_yank()
new func! Check_Results(type)
call assert_equal(g:expected_region,
\ getregion(getpos("'["), getpos("']"), #{ type: a:type }))
call assert_equal(g:expected_regionpos,
\ getregionpos(getpos("'["), getpos("']"), #{ type: a:type }))
call assert_equal(g:expected_region,
\ getregion(getpos("']"), getpos("'["), #{ type: a:type }))
call assert_equal(g:expected_regionpos,
\ getregionpos(getpos("']"), getpos("'["), #{ type: a:type }))
let g:checked = 1
endfunc
autocmd TextYankPost * autocmd TextYankPost *
\ : if v:event.operator ==? 'y' \ : if v:event.operator ==? 'y'
\ | call assert_equal([ \ | call Check_Results(v:event.regtype)
\ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 4, 0]],
\ ],
\ getregionpos(getpos("'["), getpos("']"),
\ #{ mode: visualmode() }))
\ | call assert_equal(['abcd'],
\ getregion(getpos("'["), getpos("']"),
\ #{ mode: visualmode() }))
\ | call assert_equal([
\ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 4, 0]],
\ ],
\ getregionpos(getpos("']"), getpos("'["),
\ #{ mode: visualmode() }))
\ | call assert_equal(['abcd'],
\ getregion(getpos("']"), getpos("'["),
\ #{ mode: visualmode() }))
\ | endif \ | endif
call setline(1, ['abcd', 'efghij'])
new
call setline(1, ['abcd', 'efghijk', 'lmn'])
let g:expected_region = ['abcd']
let g:expected_regionpos = [
\ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 4, 0]],
\ ]
let g:checked = 0
normal yy normal yy
call assert_equal(1, g:checked)
call Check_Results(getregtype('"'))
let g:expected_region = ['cd', 'ghijk', 'n']
let g:expected_regionpos = [
\ [[bufnr('%'), 1, 3, 0], [bufnr('%'), 1, 4, 0]],
\ [[bufnr('%'), 2, 3, 0], [bufnr('%'), 2, 7, 0]],
\ [[bufnr('%'), 3, 3, 0], [bufnr('%'), 3, 3, 0]],
\ ]
let g:checked = 0
call feedkeys("gg0ll\<C-V>jj$y", 'tx')
call assert_equal(1, g:checked)
call Check_Results(getregtype('"'))
let g:expected_region = ['bc', 'fg', 'mn']
let g:expected_regionpos = [
\ [[bufnr('%'), 1, 2, 0], [bufnr('%'), 1, 3, 0]],
\ [[bufnr('%'), 2, 2, 0], [bufnr('%'), 2, 3, 0]],
\ [[bufnr('%'), 3, 2, 0], [bufnr('%'), 3, 3, 0]],
\ ]
let g:checked = 0
call feedkeys("gg0l\<C-V>jjly", 'tx')
call assert_equal(1, g:checked)
call Check_Results(getregtype('"'))
bwipe! bwipe!
unlet g:expected_region
unlet g:expected_regionpos
unlet g:checked
autocmd! TextYankPost
delfunc Check_Results
endfunc endfunc
func Test_visual_block_cursor_delete() func Test_visual_block_cursor_delete()

View File

@@ -704,6 +704,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 */
/**/
443,
/**/ /**/
442, 442,
/**/ /**/