patch 9.2.0547: "%v" in 'errorformat' is affected by 'tabstop'

Commit: 
https://github.com/vim/vim/commit/44dcad20f2781ce5c1bd9a851212377859cc5bea
Author: Hirohito Higashi <[email protected]>
Date:   Thu May 28 19:18:38 2026 +0000

    patch 9.2.0547: "%v" in 'errorformat' is affected by 'tabstop'
    
    Problem:  The "%v" item in 'errorformat' interprets the reported
              screen column using the buffer's 'tabstop', so the cursor
              jumps to the wrong column when 'tabstop' is not 8
              (vimpostor).
    Solution: When resolving a "%v" column, always count a <tab> as 8
              screen columns, independent of 'tabstop', matching the
              column numbers reported by compilers; keep the multi-byte
              handling.  Also use "%v" in the gcc compiler file and
              update the documentation (Hirohito Higashi).
    
    fixes:  #20321
    closes: #20359
    
    Co-Authored-By: vimpostor <[email protected]>
    Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
    Signed-off-by: Hirohito Higashi <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/runtime/compiler/gcc.vim b/runtime/compiler/gcc.vim
index 1d5900eb2..6fe751c50 100644
--- a/runtime/compiler/gcc.vim
+++ b/runtime/compiler/gcc.vim
@@ -7,6 +7,7 @@
 "                      added line suggested by Anton Lindqvist 2016 Mar 31
 "                      2024 Apr 03 by The Vim Project (removed :CompilerSet 
definition)
 "                      2025 Dec 17 by The Vim Project (correctly parse: 'make: 
*** [Makefile:2: all] Error 1')
+"                      2026 May 28 by The Vim Project (Use %v to parse column 
number)
 
 if exists("current_compiler")
   finish
@@ -24,9 +25,9 @@ CompilerSet errorformat=
       \"%f\"%*\D%l:\ %m,
       \%-G%f:%l:\ %trror:\ (Each\ undeclared\ identifier\ is\ reported\ only\ 
once,
       \%-G%f:%l:\ %trror:\ for\ each\ function\ it\ appears\ in.),
-      \%f:%l:%c:\ %trror:\ %m,
-      \%f:%l:%c:\ %tarning:\ %m,
-      \%f:%l:%c:\ %m,
+      \%f:%l:%v:\ %trror:\ %m,
+      \%f:%l:%v:\ %tarning:\ %m,
+      \%f:%l:%v:\ %m,
       \%f:%l:\ %trror:\ %m,
       \%f:%l:\ %tarning:\ %m,
       \%f:%l:\ %m,
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index 581d00b7a..4b24d1298 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -1,4 +1,4 @@
-*quickfix.txt*  For Vim version 9.2.  Last change: 2026 Feb 14
+*quickfix.txt*  For Vim version 9.2.  Last change: 2026 May 28
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -1821,9 +1821,9 @@ Basic items
        %c              column number (finds a number representing character
                        column of the error, byte index, a <tab> is 1
                        character column)
-       %v              virtual column number (finds a number representing
-                       screen column of the error (1 <tab> == 8 screen
-                       columns))
+       %v              virtual column number (finds a number representing the
+                       screen column of the error, where a <tab> is always 8
+                       screen columns regardless of 'tabstop')
        %k              end column number (finds a number representing
                        the character column of the error, byte index, or a
                        number representing screen end column of the error if
diff --git a/src/quickfix.c b/src/quickfix.c
index 3fe015ee5..2470902fd 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -3626,6 +3626,32 @@ qf_jump_edit_buffer(
     return retval;
 }
 
+/*
+ * Return the byte index in the current line for screen column "vcol"
+ * (zero-based).  A <tab> is always counted as 8 screen columns, matching the
+ * column numbers compilers report for the "%v" item in 'errorformat',
+ * regardless of the buffer's 'tabstop'.
+ */
+    static int
+qf_screen_col_to_idx(colnr_T vcol)
+{
+    char_u     *line = ml_get_curline();
+    char_u     *p = line;
+    colnr_T    col = 0;
+
+    while (*p != NUL && col < vcol)
+    {
+       if (*p == TAB)
+           col += 8 - (col % 8);
+       else
+           col += ptr2cells(p);
+       if (col > vcol)
+           break;
+       MB_PTR_ADV(p);
+    }
+    return (int)(p - line);
+}
+
 /*
  * Go to the error line in the current file using either line/column number or
  * a search pattern.
@@ -3653,7 +3679,7 @@ qf_jump_goto_line(
        {
            curwin->w_cursor.coladd = 0;
            if (qf_viscol == TRUE)
-               coladvance(qf_col - 1);
+               curwin->w_cursor.col = qf_screen_col_to_idx(qf_col - 1);
            else
                curwin->w_cursor.col = qf_col - 1;
            curwin->w_set_curswant = true;
diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim
index e1dbaa7c5..c656d205f 100644
--- a/src/testdir/test_quickfix.vim
+++ b/src/testdir/test_quickfix.vim
@@ -5004,6 +5004,34 @@ func Test_viscol()
   set efm&
 endfunc
 
+" Test that '%v' is not affected by 'tabstop': a <tab> is always counted as
+" 8 screen columns, matching the column numbers reported by compilers.
+func Test_viscol_tabstop()
+  enew
+  call writefile(["    ABCDEFGH"], 'Xfile1', 'D')
+  edit Xfile1
+  set efm=%f:%l:%v:%m
+
+  " gcc reports column 9 for 'A' (the <tab> expands to 8 columns).  The jump
+  " must land on 'A' (byte 2) for any 'tabstop' value.
+  for ts in [8, 4, 2, 13]
+    exe 'setlocal tabstop=' .. ts
+    cexpr "Xfile1:1:9:XX"
+    call assert_equal(2, col('.'), 'tabstop=' .. ts)
+  endfor
+
+  " A multi-byte character after the tab: 'ä' is 2 bytes but 1 screen cell,
+  " so screen column 10 is the next character 'b' (byte 4).
+  call writefile(["    äbc"], 'Xfile1')
+  edit! Xfile1
+  setlocal tabstop=4
+  cexpr "Xfile1:1:10:XX"
+  call assert_equal(4, col('.'))
+
+  enew | only
+  set efm&
+endfunc
+
 " Test for the quickfix window buffer
 func Xqfbuf_test(cchar)
   call s:setup_commands(a:cchar)
diff --git a/src/version.c b/src/version.c
index 4382b5fdd..5fda77f1b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -729,6 +729,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    547,
 /**/
     546,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1wSgQe-00BONF-MO%40256bit.org.

Raspunde prin e-mail lui