Try this:
command -bar -bang Ls call s:ls(<bang>0)
function s:ls(bang) abort
let bufnrs = range(1, bufnr('$'))
call filter(bufnrs, a:bang ? {_, v -> bufexists(v)} : {_, v -> buflisted(v)})
let bufnames = copy(bufnrs)
\ ->map({_, v -> bufname(v)->fnamemodify(':t')})
let uniq_flags = copy(bufnames)->map({_, v -> count(bufnames, v) == 1})
let items = map(bufnrs, {i, v -> #{
\ bufnr: v,
\ text: s:gettext(v, uniq_flags[i]),
\ }})
call setloclist(0, [], ' ', #{
\ items: items,
\ title: 'ls' .. (a:bang ? '!' : ''),
\ quickfixtextfunc: 's:quickfixtextfunc',
\ })
lopen
nmap <buffer><nowait><expr><silent> <cr> <sid>Cr()
endfunction
function s:Cr()
if w:quickfix_title =~# '^ls!\=$'
let locid = win_getid()
return "\<c-w>\<cr>\<plug>(close-location-window)" .. locid .. "\<cr>\<plug>(verticalize)"
else
return "\<c-w>\<cr>\<plug>(verticalize)"
endif
endfunction
nnoremap <plug>(close-location-window) :<c-u>call <sid>CloseLocationWindow()<cr>
nnoremap <plug>(verticalize) :<c-u>wincmd L<cr>
function s:CloseLocationWindow()
let locid = input('')->str2nr()
call win_execute(locid, 'close')
endfunction
function s:gettext(v, is_uniq) abort
let format = ' %*d%s%s%s%s%s %s'
let bufnr = [bufnr('$')->len(), a:v]
let buflisted = !buflisted(a:v) ? 'u': ' '
let cur_or_alt = a:v == bufnr('%') ? '%' : a:v == bufnr('#') ? '#' : ' '
let active_or_hidden = win_findbuf(a:v)->empty() ? 'h' : 'a'
let modifiable = getbufvar(a:v, '&ma', 0) ? ' ' : '-'
let modified = getbufvar(a:v, '&mod', 0) ? '+' : ' '
let bufname = bufname(a:v)->empty()
\ ? '[No Name]'
\ : bufname(a:v)->fnamemodify(a:is_uniq ? ':t' : ':p')
return call('printf', [format]
\ + bufnr
\ + [buflisted, cur_or_alt, active_or_hidden, modifiable, modified, bufname])
endfunction
function s:quickfixtextfunc(info) abort
let items = getloclist(a:info.winid, #{id : a:info.id, items : 1}).items
let l = []
for idx in range(a:info.start_idx - 1, a:info.end_idx - 1)
call add(l, items[idx].text)
endfor
return l
endfunction
It installs a :Ls
command which should display a simplified buffer list in the location window. Press Enter on an entry to jump to the buffer.
Just like with the builtin :ls
, append a bang (:Ls!
) to include the unlisted buffers.
This requires a recent Vim version which includes these patches:
- 8.2.0869 it is not possible to customize the quickfix window contents
- 8.2.0933 'quickfixtextfunc' does not get window ID of location list
- 8.2.0959 using 'quickfixtextfunc' is a bit slow
To gain in efficiency, readability and reliability, you could rewrite the code in Vim9 script:
vim9script
command -bar -bang Ls Ls(<bang>0)
def Ls(bang: any)
var bufnrs: list<number> = range(1, bufnr('$'))
bufnrs->filter(bang
? (_, v: number): bool => bufexists(v)
: (_, v: number): bool => buflisted(v)
)
var bufnames: list<string> = copy(bufnrs)
->mapnew((_, v: number): string => bufname(v)->fnamemodify(':t'))
var uniq_flags: list<bool> = copy(bufnames)
->mapnew((_, v: string): bool => count(bufnames, v) == 1)
var items: list<dict<any>> = bufnrs
->mapnew((i: number, v: number) => ({
bufnr: v,
text: Gettext(v, uniq_flags[i]),
}))
setloclist(0, [], ' ', {
items: items,
title: 'ls' .. (bang ? '!' : ''),
quickfixtextfunc: 'Quickfixtextfunc',
})
lopen
nmap <buffer><nowait><expr><silent> <cr> <sid>Cr()
enddef
def Cr(): string
if w:quickfix_title =~ '^ls!\=$'
var locid: number = win_getid()
return "\<c-w>\<cr>\<plug>(close-location-window)" .. locid
.. "\<cr>\<plug>(verticalize)"
else
return "\<c-w>\<cr>\<plug>(verticalize)"
endif
enddef
nnoremap <plug>(close-location-window) :<c-u>call <sid>CloseLocationWindow()<cr>
nnoremap <plug>(verticalize) :<c-u>wincmd L<cr>
def CloseLocationWindow()
var locid: number = input('')->str2nr()
win_execute(locid, 'close')
enddef
def Gettext(v: number, is_uniq: bool): string
var format: string = ' %*d%s%s%s%s%s %s'
var bufnr: list<number> = [bufnr('$')->len(), v]
var buflisted: string = !buflisted(v) ? 'u' : ' '
var cur_or_alt: string = v == bufnr('%') ? '%' : v == bufnr('#') ? '#' : ' '
var active_or_hidden: string = win_findbuf(v)->empty() ? 'h' : 'a'
var modifiable: string = getbufvar(v, '&ma', 0) ? ' ' : '-'
var modified: string = getbufvar(v, '&mod', 0) ? '+' : ' '
var bufname: string = bufname(v)->empty()
? '[No Name]'
: bufname(v)->fnamemodify(is_uniq ? ':t' : ':p')
return call('printf', [format]
+ bufnr
+ [buflisted, cur_or_alt, active_or_hidden,
modifiable, modified, bufname])
enddef
def Quickfixtextfunc(info: dict<number>): list<any>
var items: list<dict<any>> = getloclist(info.winid, {id: info.id, items: 1}).items
var l: list<string> = []
for idx in range(info.start_idx - 1, info.end_idx - 1)
add(l, items[idx].text)
endfor
return l
enddef
This requires an even more recent Vim version. It works on 8.2.2332.
You don't have to write the code in your vimrc, just put it in ~/.vim/plugin/myls.vim
. Test it; keep it as long as you find it useful; remove it once you find something better.
For more info, see: