Severity: low · Category: bug
Location: plugin/statusline.vim — StlTabLabel(), lines 191-203 (specifically the return at line 202); consumed by set tabline=%!StlTabLine() at line 219
What's wrong
StlTabLabel() returns the raw basename (fnamemodify(l:name, ':t')) embedded directly into the string that StlTabLine() builds, and that whole string is evaluated as statusline format codes because the tabline is set with %!StlTabLine(). Unlike the active/inactive statuslines (which pass the filename through a plain %{StlFilename()} expression whose result is NOT re-interpreted), text spliced directly into a %!-evaluated format string IS scanned for % items. Any % in a filename therefore gets consumed as a statusline item (e.g. %c becomes the column number, %l the line number), corrupting the tab label. % is a legal filename character on both Linux and macOS (e.g. 100%done.txt, URL-encoded names, generated files), so this is a realistic correctness/robustness gap. Note the project's own CLAUDE.md conventions call out escaping for execute (/, \, |); the analogous statusline escape (%->%%) is simply missing here.
Evidence
Code (statusline.vim):
191 function! StlTabLabel(a:n) ...
195 let l:name = fnamemodify(l:name, ':t')
...
202 return ' ' . l:name . ' ' " raw name, no %-escaping
219 set tabline=%!StlTabLine() " %! => result is parsed for % items
Empirical proof (vim 9.0, -u NONE, sourcing the real file):
File on disk: tabtest2/pct%cfile.txt
Rendered tab label: ' pct1file.txt ' (the %c was evaluated to the column 1; literal name lost)
After applying substitute(l:name,'%','%%','g'): ' pct%cfile.txt ' (correct)
The active/inactive statuslines are unaffected because they use plain %{StlFilename()} whose output Vim does not re-scan for % (verified separately: a buffer named file%c.txt renders as literal Xfile%c.txtX).
Suggested fix
Escape % before returning the label in StlTabLabel(): after computing l:name (and before/after appending the ' [+]' modified marker), add let l:name = substitute(l:name, '%', '%%', 'g'). Apply it to the basename only (not the surrounding spaces), e.g.:
let l:name = fnamemodify(l:name, ':t')
if empty(l:name) | let l:name = '[No Name]' | endif
let l:name = substitute(l:name, '%', '%%', 'g')
if getbufvar(...,'&modified') | let l:name .= ' [+]' | endif
return ' ' . l:name . ' '
Filed from an automated multi-agent source review (2026-05-29); finding adversarially verified at high confidence. Line numbers reflect the audit-fixes-2026-05 working tree.
Severity: low · Category: bug
Location:
plugin/statusline.vim— StlTabLabel(), lines 191-203 (specifically the return at line 202); consumed byset tabline=%!StlTabLine()at line 219What's wrong
StlTabLabel()returns the raw basename (fnamemodify(l:name, ':t')) embedded directly into the string thatStlTabLine()builds, and that whole string is evaluated as statusline format codes because the tabline is set with%!StlTabLine(). Unlike the active/inactive statuslines (which pass the filename through a plain%{StlFilename()}expression whose result is NOT re-interpreted), text spliced directly into a%!-evaluated format string IS scanned for%items. Any%in a filename therefore gets consumed as a statusline item (e.g.%cbecomes the column number,%lthe line number), corrupting the tab label.%is a legal filename character on both Linux and macOS (e.g.100%done.txt, URL-encoded names, generated files), so this is a realistic correctness/robustness gap. Note the project's own CLAUDE.md conventions call out escaping forexecute(/,\,|); the analogous statusline escape (%->%%) is simply missing here.Evidence
Code (statusline.vim):
191 function! StlTabLabel(a:n) ...
195 let l:name = fnamemodify(l:name, ':t')
...
202 return ' ' . l:name . ' ' " raw name, no %-escaping
219 set tabline=%!StlTabLine() " %! => result is parsed for % items
Empirical proof (vim 9.0, -u NONE, sourcing the real file):
File on disk: tabtest2/pct%cfile.txt
Rendered tab label: ' pct1file.txt ' (the
%cwas evaluated to the column1; literal name lost)After applying substitute(l:name,'%','%%','g'): ' pct%cfile.txt ' (correct)
The active/inactive statuslines are unaffected because they use plain
%{StlFilename()}whose output Vim does not re-scan for%(verified separately: a buffer named file%c.txt renders as literalXfile%c.txtX).Suggested fix
Escape
%before returning the label in StlTabLabel(): after computing l:name (and before/after appending the ' [+]' modified marker), addlet l:name = substitute(l:name, '%', '%%', 'g'). Apply it to the basename only (not the surrounding spaces), e.g.:let l:name = fnamemodify(l:name, ':t')
if empty(l:name) | let l:name = '[No Name]' | endif
let l:name = substitute(l:name, '%', '%%', 'g')
if getbufvar(...,'&modified') | let l:name .= ' [+]' | endif
return ' ' . l:name . ' '
Filed from an automated multi-agent source review (2026-05-29); finding adversarially verified at high confidence. Line numbers reflect the
audit-fixes-2026-05working tree.