patch 9.1.0423: getregionpos() wrong with blockwise mode and multibyte

Problem:  getregionpos() wrong with blockwise mode and multibyte.
Solution: Use textcol and textlen instead of start_vcol and end_vcol.
          Handle coladd properly (zeertzjq).

Also remove unnecessary buflist_findnr() in add_regionpos_range(), as
getregionpos() has already switched buffer.

closes: #14805

Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
zeertzjq
2024-05-20 14:00:31 +02:00
committed by Christian Brabandt
parent 22029edb6c
commit c95e64f41f
5 changed files with 135 additions and 65 deletions

View File

@ -1,4 +1,4 @@
*builtin.txt* For Vim version 9.1. Last change: 2024 May 18
*builtin.txt* For Vim version 9.1. Last change: 2024 May 20
VIM REFERENCE MANUAL by Bram Moolenaar
@ -4341,10 +4341,12 @@ getregionpos({pos1}, {pos2} [, {opts}]) *getregionpos()*
"bufnum" is the buffer number.
"lnum" and "col" are the position in the buffer. The first
column is 1.
The "off" number is zero, unless 'virtualedit' is used. Then
it is the offset in screen columns from the start of the
character. E.g., a position within a <Tab> or after the last
character.
If the "off" number of a starting position is non-zero, it is
the offset in screen columns from the start of the character.
E.g., a position within a <Tab> or after the last character.
If the "off" number of an ending position is non-zero, it is
the character's number of cells included in the selection,
otherwise the whole character is included.
Can also be used as a |method|: >
getpos('.')->getregionpos(getpos("'a"))

View File

@ -5488,11 +5488,11 @@ block_def2str(struct block_def *bd)
getregionpos(
typval_T *argvars,
typval_T *rettv,
pos_T *p1, pos_T *p2,
pos_T *p1,
pos_T *p2,
int *inclusive,
int *region_type,
oparg_T *oa,
int *fnum)
oparg_T *oa)
{
int fnum1 = -1, fnum2 = -1;
char_u *type;
@ -5542,7 +5542,6 @@ getregionpos(
}
findbuf = fnum1 != 0 ? buflist_findnr(fnum1) : curbuf;
*fnum = fnum1 != 0 ? fnum1 : curbuf->b_fnum;
if (findbuf == NULL || findbuf->b_ml.ml_mfp == NULL)
{
emsg(_(e_buffer_is_not_loaded));
@ -5658,7 +5657,6 @@ f_getregion(typval_T *argvars, typval_T *rettv)
int inclusive = TRUE;
int region_type = -1;
oparg_T oa;
int fnum;
buf_T *save_curbuf;
int save_virtual;
@ -5669,7 +5667,7 @@ f_getregion(typval_T *argvars, typval_T *rettv)
save_virtual = virtual_op;
if (getregionpos(argvars, rettv,
&p1, &p2, &inclusive, &region_type, &oa, &fnum) == FAIL)
&p1, &p2, &inclusive, &region_type, &oa) == FAIL)
return;
for (lnum = p1.lnum; lnum <= p2.lnum; lnum++)
@ -5706,31 +5704,18 @@ f_getregion(typval_T *argvars, typval_T *rettv)
}
}
// getregionpos() breaks curbuf and virtual_op
// getregionpos() may change curbuf and virtual_op
curbuf = save_curbuf;
curwin->w_buffer = curbuf;
virtual_op = save_virtual;
}
static void
add_regionpos_range(
typval_T *rettv,
int bufnr,
int lnum1,
int col1,
int coladd1,
int lnum2,
int col2,
int coladd2)
add_regionpos_range(typval_T *rettv, pos_T p1, pos_T p2)
{
list_T *l1, *l2, *l3;
buf_T *findbuf;
int max_col1, max_col2;
findbuf = bufnr != 0 ? buflist_findnr(bufnr) : curbuf;
if (findbuf == NULL || findbuf->b_ml.ml_mfp == NULL)
return;
l1 = list_alloc();
if (l1 == NULL)
return;
@ -5771,18 +5756,17 @@ add_regionpos_range(
return;
}
max_col1 = ml_get_len(p1.lnum);
list_append_number(l2, curbuf->b_fnum);
list_append_number(l2, p1.lnum);
list_append_number(l2, p1.col > max_col1 ? max_col1 : p1.col);
list_append_number(l2, p1.coladd);
max_col1 = ml_get_buf_len(findbuf, lnum1);
list_append_number(l2, bufnr);
list_append_number(l2, lnum1);
list_append_number(l2, col1 > max_col1 ? max_col1 : col1);
list_append_number(l2, coladd1);
max_col2 = ml_get_buf_len(findbuf, lnum2);
list_append_number(l3, bufnr);
list_append_number(l3, lnum2);
list_append_number(l3, col2 > max_col2 ? max_col2 : col2);
list_append_number(l3, coladd2);
max_col2 = ml_get_len(p2.lnum);
list_append_number(l3, curbuf->b_fnum);
list_append_number(l3, p2.lnum);
list_append_number(l3, p2.col > max_col2 ? max_col2 : p2.col);
list_append_number(l3, p2.coladd);
}
/*
@ -5795,7 +5779,6 @@ f_getregionpos(typval_T *argvars, typval_T *rettv)
int inclusive = TRUE;
int region_type = -1;
oparg_T oa;
int fnum;
int lnum;
buf_T *save_curbuf;
@ -5805,38 +5788,52 @@ f_getregionpos(typval_T *argvars, typval_T *rettv)
save_virtual = virtual_op;
if (getregionpos(argvars, rettv,
&p1, &p2, &inclusive, &region_type, &oa, &fnum) == FAIL)
&p1, &p2, &inclusive, &region_type, &oa) == FAIL)
return;
for (lnum = p1.lnum; lnum <= p2.lnum; lnum++)
{
struct block_def bd;
int start_col, end_col;
pos_T ret_p1, ret_p2;
if (region_type == MLINE)
{
start_col = 1;
end_col = MAXCOL;
}
else if (region_type == MBLOCK)
{
block_prep(&oa, &bd, lnum, FALSE);
start_col = bd.start_vcol + 1;
end_col = bd.end_vcol;
}
else if (p1.lnum < lnum && lnum < p2.lnum)
{
start_col = 1;
end_col = MAXCOL;
ret_p1.col = 1;
ret_p1.coladd = 0;
ret_p2.col = MAXCOL;
ret_p2.coladd = 0;
}
else
{
start_col = p1.lnum == lnum ? p1.col + 1 : 1;
end_col = p2.lnum == lnum ? p2.col + 1 : MAXCOL;
if (region_type == MBLOCK)
block_prep(&oa, &bd, lnum, FALSE);
else
charwise_block_prep(p1, p2, &bd, lnum, inclusive);
if (bd.startspaces > 0)
{
ret_p1.col = bd.textcol;
ret_p1.coladd = bd.start_char_vcols - bd.startspaces;
}
else
{
ret_p1.col = bd.textcol + 1;
ret_p1.coladd = 0;
}
if (bd.endspaces > 0)
{
ret_p2.col = bd.textcol + bd.textlen + 1;
ret_p2.coladd = bd.endspaces;
}
else
{
ret_p2.col = bd.textcol + bd.textlen;
ret_p2.coladd = 0;
}
}
add_regionpos_range(rettv, fnum, lnum, start_col,
p1.coladd, lnum, end_col, p2.coladd);
ret_p1.lnum = lnum;
ret_p2.lnum = lnum;
add_regionpos_range(rettv, ret_p1, ret_p2);
}
// getregionpos() may change curbuf and virtual_op

View File

@ -2451,6 +2451,7 @@ charwise_block_prep(
p = ml_get(lnum);
bdp->startspaces = 0;
bdp->endspaces = 0;
bdp->start_char_vcols = 0;
if (lnum == start.lnum)
{
@ -2462,8 +2463,8 @@ charwise_block_prep(
{
// Part of a tab selected -- but don't
// double-count it.
bdp->startspaces = (ce - cs + 1)
- start.coladd;
bdp->start_char_vcols = ce - cs + 1;
bdp->startspaces = bdp->start_char_vcols - start.coladd;
if (bdp->startspaces < 0)
bdp->startspaces = 0;
startcol++;
@ -2483,19 +2484,16 @@ charwise_block_prep(
// of multi-byte char.
&& (*mb_head_off)(p, p + endcol) == 0))
{
if (start.lnum == end.lnum
&& start.col == end.col)
if (start.lnum == end.lnum && start.col == end.col)
{
// Special case: inside a single char
is_oneChar = TRUE;
bdp->startspaces = end.coladd
- start.coladd + inclusive;
bdp->startspaces = end.coladd - start.coladd + inclusive;
endcol = startcol;
}
else
{
bdp->endspaces = end.coladd
+ inclusive;
bdp->endspaces = end.coladd + inclusive;
endcol -= inclusive;
}
}
@ -2507,6 +2505,7 @@ charwise_block_prep(
bdp->textlen = 0;
else
bdp->textlen = endcol - startcol + inclusive;
bdp->textcol = startcol;
bdp->textstart = p + startcol;
}

View File

@ -1640,6 +1640,7 @@ func Test_visual_getregion()
#" Visual mode
call cursor(1, 1)
call feedkeys("\<ESC>vjl", 'tx')
call assert_equal(['one', 'tw'],
\ 'v'->getpos()->getregion(getpos('.')))
call assert_equal([
@ -1647,6 +1648,7 @@ func Test_visual_getregion()
\ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 2, 0]]
\ ],
\ 'v'->getpos()->getregionpos(getpos('.')))
call assert_equal(['one', 'tw'],
\ '.'->getpos()->getregion(getpos('v')))
call assert_equal([
@ -1654,18 +1656,21 @@ func Test_visual_getregion()
\ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 2, 0]]
\ ],
\ '.'->getpos()->getregionpos(getpos('v')))
call assert_equal(['o'],
\ 'v'->getpos()->getregion(getpos('v')))
call assert_equal([
\ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 1, 0]],
\ ],
\ 'v'->getpos()->getregionpos(getpos('v')))
call assert_equal(['w'],
\ '.'->getpos()->getregion(getpos('.'), {'type': 'v' }))
call assert_equal([
\ [[bufnr('%'), 2, 2, 0], [bufnr('%'), 2, 2, 0]],
\ ],
\ '.'->getpos()->getregionpos(getpos('.'), {'type': 'v' }))
call assert_equal(['one', 'two'],
\ getpos('.')->getregion(getpos('v'), {'type': 'V' }))
call assert_equal([
@ -1673,6 +1678,7 @@ func Test_visual_getregion()
\ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 3, 0]],
\ ],
\ getpos('.')->getregionpos(getpos('v'), {'type': 'V' }))
call assert_equal(['on', 'tw'],
\ getpos('.')->getregion(getpos('v'), {'type': "\<C-v>" }))
call assert_equal([
@ -1815,6 +1821,12 @@ func Test_visual_getregion()
call assert_equal(range(10)->mapnew('string(v:val)'),
\ getregion([g:buf, 10, 2, 0], [g:buf, 1, 1, 0],
\ {'type': type, 'exclusive': exclusive }))
call assert_equal(range(1, 10)->mapnew('repeat([[g:buf, v:val, 1, 0]], 2)'),
\ getregionpos([g:buf, 1, 1, 0], [g:buf, 10, 2, 0],
\ {'type': type, 'exclusive': exclusive }))
call assert_equal(range(1, 10)->mapnew('repeat([[g:buf, v:val, 1, 0]], 2)'),
\ getregionpos([g:buf, 10, 2, 0], [g:buf, 1, 1, 0],
\ {'type': type, 'exclusive': exclusive }))
endfor
endfor
@ -1848,28 +1860,55 @@ func Test_visual_getregion()
\ "\U0001f1e6\u00ab\U0001f1e7\u00ab\U0001f1e8\u00ab\U0001f1e9",
\ "1234567890"
\ ])
call cursor(1, 3)
call feedkeys("\<Esc>\<C-v>ljj", 'xt')
call assert_equal(['cd', "\u00ab ", '34'],
\ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
call assert_equal([
\ [[bufnr('%'), 1, 3, 0], [bufnr('%'), 1, 4, 0]],
\ [[bufnr('%'), 2, 5, 0], [bufnr('%'), 2, 7, 1]],
\ [[bufnr('%'), 3, 3, 0], [bufnr('%'), 3, 4, 0]],
\ ],
\ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
call cursor(1, 4)
call feedkeys("\<Esc>\<C-v>ljj", 'xt')
call assert_equal(['de', "\U0001f1e7", '45'],
\ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
call assert_equal([
\ [[bufnr('%'), 1, 4, 0], [bufnr('%'), 1, 5, 0]],
\ [[bufnr('%'), 2, 7, 0], [bufnr('%'), 2, 10, 0]],
\ [[bufnr('%'), 3, 4, 0], [bufnr('%'), 3, 5, 0]],
\ ],
\ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
call cursor(1, 5)
call feedkeys("\<Esc>\<C-v>jj", 'xt')
call assert_equal(['e', ' ', '5'],
\ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
call assert_equal([
\ [[bufnr('%'), 1, 5, 0], [bufnr('%'), 1, 5, 0]],
\ [[bufnr('%'), 2, 10, 1], [bufnr('%'), 2, 10, 0]],
\ [[bufnr('%'), 3, 5, 0], [bufnr('%'), 3, 5, 0]],
\ ],
\ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
call assert_equal([
\ [[bufnr('%'), 1, 5, 0], [bufnr('%'), 1, 13, 0]],
\ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 22, 0]],
\ [[bufnr('%'), 3, 1, 0], [bufnr('%'), 3, 5, 0]],
\ ],
\ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
call cursor(1, 1)
call feedkeys("\<Esc>vj", 'xt')
call assert_equal(['abcdefghijk«', "\U0001f1e6"],
\ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
call assert_equal([
\ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 13, 0]],
\ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 4, 0]],
\ ],
\ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
#" marks on multibyte chars
:set selection=exclusive
@ -1877,12 +1916,29 @@ func Test_visual_getregion()
call setpos("'b", [0, 2, 16, 0])
call setpos("'c", [0, 2, 0, 0])
call cursor(1, 1)
call assert_equal(['ghijk', '🇨«🇩'],
\ getregion(getpos("'a"), getpos("'b"), {'type': "\<C-v>" }))
call assert_equal([
\ [[bufnr('%'), 1, 7, 0], [bufnr('%'), 1, 11, 0]],
\ [[bufnr('%'), 2, 13, 0], [bufnr('%'), 2, 22, 0]],
\ ],
\ getregionpos(getpos("'a"), getpos("'b"), {'type': "\<C-v>" }))
call assert_equal(['k«', '🇦«🇧«🇨'],
\ getregion(getpos("'a"), getpos("'b"), {'type': 'v' }))
call assert_equal([
\ [[bufnr('%'), 1, 11, 0], [bufnr('%'), 1, 13, 0]],
\ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 16, 0]],
\ ],
\ getregionpos(getpos("'a"), getpos("'b"), {'type': 'v' }))
call assert_equal(['k«'],
\ getregion(getpos("'a"), getpos("'c"), {'type': 'v' }))
call assert_equal([
\ [[bufnr('%'), 1, 11, 0], [bufnr('%'), 1, 13, 0]],
\ ],
\ getregionpos(getpos("'a"), getpos("'c"), {'type': 'v' }))
#" use inclusive selection, although 'selection' is exclusive
call setpos("'a", [0, 1, 11, 0])
@ -1975,14 +2031,28 @@ func Test_visual_getregion()
#" virtualedit
set selection=exclusive
set virtualedit=all
call cursor(1, 1)
call feedkeys("\<Esc>2lv2lj", 'xt')
call assert_equal([' c', 'x '],
\ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
call assert_equal([
\ [[bufnr('%'), 1, 2, 1], [bufnr('%'), 1, 3, 0]],
\ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 2, 3]],
\ ],
\ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
call cursor(1, 1)
call feedkeys("\<Esc>2l\<C-v>2l2j", 'xt')
call assert_equal([' ', ' ', ' '],
\ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
call assert_equal([
\ [[bufnr('%'), 1, 2, 5], [bufnr('%'), 1, 2, 0]],
\ [[bufnr('%'), 2, 2, 5], [bufnr('%'), 2, 2, 0]],
\ [[bufnr('%'), 3, 0, 0], [bufnr('%'), 3, 0, 2]],
\ ],
\ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
set virtualedit&
set selection&

View File

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