vim-patch:9.1.2017: getregionpos() depends on 'linebreak' setting (#37088)

Problem:  getregionpos() depends on 'linebreak' setting
Solution: Reset linebreak setting temporarily (McAuley Penney)

When a line is wrapped on word boundaries, getregionpos() may report a
different end column for a visual block than the cursor position used to
define the selection.

Update the blockwise calculation in getregionpos() to use the same
wrapping assumptions as visual block mode, so the reported region
matches the selection boundaries.

Add a regression test that forces wrapping and checks that the end
position stays consistent under "setlocal wrap" and "setlocal
linebreak".

closes: vim/vim#19006

8ea0e7205c

Co-authored-by: McAuley Penney <jacobmpenney@gmail.com>
This commit is contained in:
zeertzjq
2025-12-24 09:48:59 +08:00
committed by GitHub
parent 2a2c366a3e
commit d7b882697b
3 changed files with 73 additions and 2 deletions

View File

@@ -2281,8 +2281,10 @@ static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2
}
} else if (*region_type == kMTBlockWise) {
colnr_T sc1, ec1, sc2, ec2;
const bool lbr_saved = reset_lbr();
getvvcol(curwin, p1, &sc1, NULL, &ec1);
getvvcol(curwin, p2, &sc2, NULL, &ec2);
restore_lbr(lbr_saved);
oap->motion_type = kMTBlockWise;
oap->inclusive = true;
oap->op_type = OP_NOP;

View File

@@ -2077,7 +2077,7 @@ theend:
/// Reset 'linebreak' and take care of side effects.
/// @return the previous value, to be passed to restore_lbr().
static bool reset_lbr(void)
bool reset_lbr(void)
{
if (!curwin->w_p_lbr) {
return false;
@@ -2089,7 +2089,7 @@ static bool reset_lbr(void)
}
/// Restore 'linebreak' and take care of side effects.
static void restore_lbr(bool lbr_saved)
void restore_lbr(bool lbr_saved)
{
if (curwin->w_p_lbr || !lbr_saved) {
return;

View File

@@ -2839,4 +2839,73 @@ func Test_visual_block_pos_update()
bw!
endfunc
" Test that blockwise end position matches getpos('.')
" when 'wrap' and 'linebreak' are set
func Test_getregionpos_block_linebreak_matches_getpos()
CheckFeature linebreak
new
setlocal buftype=
setlocal bufhidden=wipe
setlocal noswapfile
setlocal wrap
setlocal linebreak
setlocal breakat=\ \t
setlocal nonumber norelativenumber
setlocal signcolumn=no
setlocal foldcolumn=0
call setline(1, '1111111111 2222222222 3333333333 4444444444 5555555555 6666666666 7777777777 8888888888')
" Force wrapping deterministically by shrinking the screen width.
let save_columns = &columns
let moved = 0
for c in [30, 20, 15, 10]
execute 'set columns=' .. c
redraw!
normal! gg0
let row0 = winline()
normal! gj
let row1 = winline()
if row1 > row0
let moved = 1
break
endif
endfor
call assert_true(moved)
" Move a bit right so we are not at column 1, then go back up one screen line.
normal! 5l
normal! gk
let row2 = winline()
call assert_equal(row0, row2)
" Start Visual block and move down one screen line to the previous position.
execute "normal! \<C-V>"
normal! gj
let row3 = winline()
call assert_equal(row1, row3)
let p1 = getpos('v')
let p2 = getpos('.')
" Sanity: block selection is within the same wrapped buffer line.
call assert_equal(1, p1[1])
call assert_equal(1, p2[1])
" For blockwise region, getregionpos() should not report an end position
" different from the {pos2} we passed in.
let segs = getregionpos(p1, p2, #{ type: "\<C-V>", exclusive: v:false })
call assert_equal(1, len(segs))
let endp = segs[0][1]
call assert_equal(p2[1], endp[1]) " lnum
call assert_equal(p2[2], endp[2]) " col
call assert_equal(p2[3], endp[3]) " off
let &columns = save_columns
bw!
endfunc
" vim: shiftwidth=2 sts=2 expandtab