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

0 views
Skip to first unread message

Christian Brabandt

unread,
3:30 PM (2 hours ago) 3:30 PM
to vim...@googlegroups.com
patch 9.2.0547: "%v" in 'errorformat' is affected by 'tabstop'

Commit: https://github.com/vim/vim/commit/44dcad20f2781ce5c1bd9a851212377859cc5bea
Author: Hirohito Higashi <h.eas...@gmail.com>
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 <21310755+...@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <nor...@anthropic.com>
Signed-off-by: Hirohito Higashi <h.eas...@gmail.com>
Signed-off-by: Christian Brabandt <c...@256bit.org>

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,
/**/
Reply all
Reply to author
Forward
0 new messages