]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0547: "%v" in 'errorformat' is affected by 'tabstop' v9.2.0547
authorHirohito Higashi <h.east.727@gmail.com>
Thu, 28 May 2026 19:18:38 +0000 (19:18 +0000)
committerChristian Brabandt <cb@256bit.org>
Thu, 28 May 2026 19:18:38 +0000 (19:18 +0000)
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 <21310755+vimpostor@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
runtime/compiler/gcc.vim
runtime/doc/quickfix.txt
src/quickfix.c
src/testdir/test_quickfix.vim
src/version.c

index 1d5900eb27bbf36f78ccbb2d6e9558c817c330db..6fe751c50a6fb9bc18cf019afd2088d585e5547f 100644 (file)
@@ -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,
index 581d00b7a788ecb65d6998f45ce892ca6ce5f99c..4b24d12980f57c1513538791858d550ec04f4933 100644 (file)
@@ -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
index 3fe015ee58c6bbae06caa1db377de982adf31d23..2470902fd182183f0738479de73ac319e84444f8 100644 (file)
@@ -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;
index e1dbaa7c59b2d1b5bbbc8b4a963ebc2462824e42..c656d205f029ebf82bd2051936ecb56adeaaee53 100644 (file)
@@ -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(["\tABCDEFGH"], '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(["\tä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)
index 4382b5fddb34a949a2f06be0ef039295a6ccb22c..5fda77f1bc270db1123a023a2a9cb285a6aabb7b 100644 (file)
@@ -729,6 +729,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    547,
 /**/
     546,
 /**/