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

2 views
Skip to first unread message

Christian Brabandt

unread,
May 24, 2024, 1:15:12 PMMay 24
to vim...@googlegroups.com
patch 9.1.0443: Can't use blockwise selection with width for getregion()

Commit: https://github.com/vim/vim/commit/afc2295c2201ae87bfbb42d5f5315ad0583ccabf
Author: zeertzjq <zeer...@outlook.com>
Date: Fri May 24 19:07:12 2024 +0200

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 <zeer...@outlook.com>
Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index afd84c11e..866fab177 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -4288,14 +4288,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 |characterwise| 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()|.
diff --git a/src/evalfunc.c b/src/evalfunc.c
index a1f8a8f8e..b389085ed 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -5492,12 +5492,13 @@ getregionpos(
pos_T *p2,
int *inclusive,
int *region_type,
- oparg_T *oa)
+ oparg_T *oap)
{
int fnum1 = -1, fnum2 = -1;
char_u *type;
buf_T *findbuf;
char_u default_type[] = "v";
+ int block_width = 0;
int is_select_exclusive;
int l;

@@ -5533,8 +5534,17 @@ getregionpos(
*region_type = MCHAR;
else if (type[0] == 'V' && type[1] == NUL)
*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;
+ }
else
{
semsg(_(e_invalid_value_for_argument_str_str), "type", type);
@@ -5608,16 +5618,18 @@ getregionpos(

getvvcol(curwin, p1, &sc1, NULL, &ec1);
getvvcol(curwin, p2, &sc2, NULL, &ec2);
- oa->motion_type = MBLOCK;
- 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 = MBLOCK;
+ 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);
}

// Include the trailing byte of a multi-byte char.
diff --git a/src/testdir/test_visual.vim b/src/testdir/test_visual.vim
index d1b9c71cf..72e8aebf9 100644
--- a/src/testdir/test_visual.vim
+++ b/src/testdir/test_visual.vim
@@ -1964,6 +1964,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
@@ -2542,30 +2550,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()
diff --git a/src/version.c b/src/version.c
index b430e3515..87a2ff442 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 443,
/**/
442,
/**/
Reply all
Reply to author
Forward
0 new messages