]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.2017: getregionpos() depends on 'linebreak' setting v9.1.2017
authorMcAuley Penney <jacobmpenney@gmail.com>
Tue, 23 Dec 2025 20:51:25 +0000 (20:51 +0000)
committerChristian Brabandt <cb@256bit.org>
Tue, 23 Dec 2025 20:51:25 +0000 (20:51 +0000)
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: #19006

Signed-off-by: McAuley Penney <jacobmpenney@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/evalfunc.c
src/ops.c
src/proto/ops.pro
src/testdir/test_visual.vim
src/version.c

index be654a5879b7956e89d940d7d59c8df7a65a2a06..5aeca60d48a469d4d2035f60095cce0146f94379 100644 (file)
@@ -6175,8 +6175,17 @@ getregionpos(
     {
        colnr_T sc1, ec1, sc2, ec2;
 
+       #ifdef FEAT_LINEBREAK
+       int     lbr_saved = reset_lbr();
+       #endif
+
        getvvcol(curwin, p1, &sc1, NULL, &ec1);
        getvvcol(curwin, p2, &sc2, NULL, &ec2);
+
+       #ifdef FEAT_LINEBREAK
+       restore_lbr(lbr_saved);
+       #endif
+
        oap->motion_type = MBLOCK;
        oap->inclusive = TRUE;
        oap->op_type = OP_NOP;
index a7f0f041d0208a60d769479281b139db1cb7b40c..7310efae83e9560d2155e05c474b830232822754 100644 (file)
--- a/src/ops.c
+++ b/src/ops.c
@@ -2398,7 +2398,7 @@ theend:
  * Reset 'linebreak' and take care of side effects.
  * Returns the previous value, to be passed to restore_lbr().
  */
-    static int
+    int
 reset_lbr(void)
 {
     if (!curwin->w_p_lbr)
@@ -2412,7 +2412,7 @@ reset_lbr(void)
 /*
  * Restore 'linebreak' and take care of side effects.
  */
-    static void
+    void
 restore_lbr(int lbr_saved)
 {
     if (curwin->w_p_lbr || !lbr_saved)
index bebe63553b0280f5ee06ba767bc419959bddbc6f..b7c6a33b413c6383c91623d4fbe92158d63151ff 100644 (file)
@@ -22,4 +22,6 @@ char *did_set_operatorfunc(optset_T *args);
 void free_operatorfunc_option(void);
 int set_ref_in_opfunc(int copyID);
 void do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank);
+int reset_lbr(void);
+void restore_lbr(int lbr_saved);
 /* vim: set ft=c : */
index 557271a06cb04483d8f535afa12e1572c6d0cc9d..f4a010635e284f722d957ef507ffb54381c3527d 100644 (file)
@@ -2835,4 +2835,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
index fdc6ed8f522683ffe0d20dd8e9e52d91accb20d7..877cdf99d58a1c0768f89ef348b939d7c5cb871a 100644 (file)
@@ -734,6 +734,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2017,
 /**/
     2016,
 /**/