vim-patch:9.1.0443: Can't use blockwise selection with width for getregion() (#28985)

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: vim/vim#14842

afc2295c22
This commit is contained in:
zeertzjq 2024-05-25 05:19:46 +08:00 committed by GitHub
parent 28c04948a1
commit 06347a64ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 96 additions and 48 deletions

View File

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

View File

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

View File

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

View File

@ -2824,7 +2824,7 @@ static char *block_def2str(struct block_def *bd)
}
static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2,
bool *const inclusive, MotionType *region_type, oparg_T *oa)
bool *const inclusive, MotionType *region_type, oparg_T *oap)
FUNC_ATTR_NONNULL_ALL
{
tv_list_alloc_ret(rettv, kListLenMayKnow);
@ -2858,11 +2858,17 @@ static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2
type = default_type;
}
int block_width = 0;
if (type[0] == 'v' && type[1] == NUL) {
*region_type = kMTCharWise;
} else if (type[0] == 'V' && type[1] == NUL) {
*region_type = kMTLineWise;
} else if (type[0] == Ctrl_V && type[1] == NUL) {
} else if (type[0] == Ctrl_V) {
char *p = type + 1;
if (*p != NUL && ((block_width = getdigits_int(&p, false, 0)) <= 0 || *p != NUL)) {
semsg(_(e_invargNval), "type", type);
return FAIL;
}
*region_type = kMTBlockWise;
} else {
semsg(_(e_invargNval), "type", type);
@ -2926,16 +2932,18 @@ static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2
colnr_T sc1, ec1, sc2, ec2;
getvvcol(curwin, p1, &sc1, NULL, &ec1);
getvvcol(curwin, p2, &sc2, NULL, &ec2);
oa->motion_type = kMTBlockWise;
oa->inclusive = true;
oa->op_type = OP_NOP;
oa->start = *p1;
oa->end = *p2;
oa->start_vcol = MIN(sc1, sc2);
if (is_select_exclusive && ec1 < sc2 && 0 < sc2 && ec2 > ec1) {
oa->end_vcol = sc2 - 1;
oap->motion_type = kMTBlockWise;
oap->inclusive = true;
oap->op_type = OP_NOP;
oap->start = *p1;
oap->end = *p2;
oap->start_vcol = MIN(sc1, sc2);
if (block_width > 0) {
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 {
oa->end_vcol = MAX(ec1, ec2);
oap->end_vcol = MAX(ec1, ec2);
}
}

View File

@ -1968,6 +1968,14 @@ func Test_visual_getregion()
#" using invalid value for "type"
call assert_fails("call getregion(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
new
@ -2546,30 +2554,65 @@ func Test_getregion_invalid_buf()
bwipe!
endfunc
func Test_getregion_maxcol()
new
func Test_getregion_after_yank()
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 *
\ : if v:event.operator ==? 'y'
\ | 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() }))
\ | 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() }))
\ | call Check_Results(v:event.regtype)
\ | 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
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!
unlet g:expected_region
unlet g:expected_regionpos
unlet g:checked
autocmd! TextYankPost
delfunc Check_Results
endfunc
func Test_visual_block_cursor_delete()