If your Vim includes the patch 8.2.0959, you can set the 'quickfixtextfunc'
option to the name of a Vimscript function whose task is to format each entry displayed in the quickfix window.
To get the desired alignment, use a few printf()
invocations appropriately.
As an example:
set qftf=QuickFixTextFunc nowrap | syn on
fu QuickFixTextFunc(info) abort
if a:info.quickfix
let qfl = getqflist(#{id: a:info.id, items: 0}).items
else
let qfl = getloclist(a:info.winid, #{id: a:info.id, items: 0}).items
endif
let l = []
let lnum_width = range(a:info.start_idx - 1, a:info.end_idx - 1)
\ ->map({_, v -> qfl[v].lnum})
\ ->max()
\ ->len()
let col_width = range(a:info.start_idx - 1, a:info.end_idx - 1)
\ ->map({_, v -> qfl[v].col})
\ ->max()
\ ->len()
let fname_width = range(a:info.start_idx - 1, a:info.end_idx - 1)
\ ->map({_, v -> qfl[v].bufnr->bufname()->fnamemodify(':t')->strchars(1)})
\ ->max()
let type_width = range(a:info.start_idx - 1, a:info.end_idx - 1)
\ ->map({_, v -> get(s:EFM_TYPE, qfl[v].type, '')->strlen()})
\ ->max()
let errnum_width = range(a:info.start_idx - 1, a:info.end_idx - 1)
\ ->map({_, v -> qfl[v].nr})
\ ->max()
\ ->len()
for idx in range(a:info.start_idx - 1, a:info.end_idx - 1)
let e = qfl[idx]
if !e.valid
call add(l, '|| ' .. e.text)
else
if e.lnum == 0 && e.col == 0
call add(l, bufname(e.bufnr))
else
let fname = printf('%-*S', fname_width, bufname(e.bufnr)->fnamemodify(':t'))
let lnum = printf('%*d', lnum_width, e.lnum)
let col = printf('%*d', col_width, e.col)
let type = printf('%-*S', type_width, get(s:EFM_TYPE, e.type, ''))
let errnum = ''
if e.nr
let errnum = printf('%*d', errnum_width + 1, e.nr)
endif
call add(l, printf('%s|%s col %s %s%s| %s', fname, lnum, col, type, errnum, e.text))
endif
endif
endfor
return l
endfu
const s:EFM_TYPE = #{e: 'error', w: 'warning', i: 'info', n: 'note'}
helpg foobar
copen
If you care about speed, and you often deal with long quickfix lists, try to rewrite the code in Vim9 script:
vim9script
set qftf=QuickFixTextFunc nowrap | syn on
def QuickFixTextFunc(info: dict<number>): list<string>
var qfl: list<any>
if info.quickfix
qfl = getqflist({id: info.id, items: 0}).items
else
qfl = getloclist(info.winid, {id: info.id, items: 0}).items
endif
var l: list<string> = []
var lnum_width: number = range(info.start_idx - 1, info.end_idx - 1)
->map((_, v: number): number => qfl[v].lnum)
->max()
->len()
var col_width: number = range(info.start_idx - 1, info.end_idx - 1)
->map((_, v: number): number => qfl[v].col)
->max()
->len()
var fname_width: number = range(info.start_idx - 1, info.end_idx - 1)
->map((_, v: number): number => qfl[v].bufnr->bufname()->fnamemodify(':t')->strchars(true))
->max()
var type_width: number = range(info.start_idx - 1, info.end_idx - 1)
->map((_, v: number): number => get(EFM_TYPE, qfl[v].type, '')->strlen())
->max()
var errnum_width: number = range(info.start_idx - 1, info.end_idx - 1)
->map((_, v: number): number => qfl[v].nr)
->max()
->len()
for idx in range(info.start_idx - 1, info.end_idx - 1)
var e: dict<any> = qfl[idx]
if !e.valid
add(l, '|| ' .. e.text)
else
if e.lnum == 0 && e.col == 0
add(l, bufname(e.bufnr))
else
var fname: string = printf('%-*S', fname_width, bufname(e.bufnr)->fnamemodify(':t'))
var lnum: string = printf('%*d', lnum_width, e.lnum)
var col: string = printf('%*d', col_width, e.col)
var type: string = printf('%-*S', type_width, get(EFM_TYPE, e.type, ''))
var errnum = ''
if e.nr
errnum = printf('%*d', errnum_width + 1, e.nr)
endif
add(l, printf('%s|%s col %s %s%s| %s', fname, lnum, col, type, errnum, e.text))
endif
endif
endfor
return l
enddef
const EFM_TYPE = {e: 'error', w: 'warning', i: 'info', n: 'note'}
helpg foobar
copen
On my machine, it seems to be around 4 times faster.
This requires a recent Vim version. It works on 8.2.2332.
For more info, see: