Использование буферов — довольно фундаментальная часть правильного использования Vim, и, честно говоря, я какое-то время избегал их использования, когда начинал. Это странная концепция, если вы привыкли использовать любую программу с графическим интерфейсом, где чаще всего думают в терминах файлов и вкладок.

Но главной проблемой, которую мне пришлось решить, была команда :ls, которую я до сих пор нахожу громоздкой и неинтуитивной. Я использовал fzf, чтобы загрузить свой список буферов в конце, который имеет предварительный просмотр и намного проще в использовании, но я все еще немного злился на себя за то, что не смог преодолеть эту фундаментальную часть функциональности Vim без плагина.

Также есть несколько вещей, которые мне не нравятся в команде буфера fzf. Загрузка занимает слишком много времени, вы не можете удалить буферы с его помощью или открыть более одного, и мне все еще приходится обращаться к нему слишком часто.

Я начал решать эту проблему, пытаясь сделать свою собственную функцию отображения буфера, которая открывалась бы быстрее, чем fzf, а также позволяла бы мне удалять буферы. Это включало создание нового скрытого буфера, вставку содержимого списка буферов (благодаря команде :redir) и ограничение движения курсора вверх и вниз.

кстати: профессиональный совет, вы можете сохранить вывод любой команды, используя либо :redir

:redir => o | execute 'ls' | redir END | let buffers = o

…или функция execute()

:let buffers = execute('ls')

Иногда лучше использовать redir, хотя execute выглядит чище.

Для тех, кто интересуется скриптами vim, вот функция, которую я написал…

" The function's designed to take any command you want and turn it 
" into a menu list...
function! AnyList(cmd, ftype, cursorposition)
  " If we're already in the buffer menu ignore...
  if bufname("%") == "menu-list" | return | endif
  " Save the buffer list into a variable called l:list...
  silent! redir => o | execute 'silent ' . a:cmd | redir END | let      l:list = o
  " Set up the buffer-list buffer (this makes it hidden)...
  let g:anylistbuff = bufnr('menu-list', 1)
  call setbufvar(g:anylistbuff, "&buftype", "nofile")
  call bufload('menu-list')
  " Loop over each line in the buffer list and add
  " it to our empty buffer...
  let lnum = 0
  for line in split(l:list, '\n')
    let lnum += 1
    call setbufline(g:anylistbuff, lnum, line)
  endfor
  " If the user leaves the list, delete it...
  au! BufLeave menu-list execute g:anylistbuff . "bwipeout"
  " Make a new split and add the new buffer...  
  execute "sbuffer" . g:anylistbuff
  
  " Set a cursorline for the menu look and feel...
  silent! set cursorline
  
  " Give the buffer a filetype for color syntax
  exe "silent! set filetype=" . a:ftype
  
  " Depending on the list type you'll want the cursor to 
  " start in a specific position...
  exe "norm " . a:cursorposition
  " On "enter" open a buffer for the number
  " under the cursor...
  exe "map <silent> <buffer> <cr> :b " . expand("<cword>") . "<cr>"
  " On "dd" delete the buffer number under the cursor...
  exe "map <silent> <buffer> dd :bd " . expand("<cword>") . "<cr>V:g/./d\<cr>" . a:cursorposition
  " Limit movement, you can still do "w" etc, this is just to make
  " it a bit more like a menu...
  map <buffer> h <NOP>
  map <buffer> l <NOP>
  map <buffer> <esc> <c-w>c
endfunction

Теоретически это работает довольно хорошо, но требует дополнительной работы, я обнаружил, что иногда это заставляет буферы вести себя довольно странно среди других проблем, которые я сейчас не могу вспомнить, короче говоря, мне стало скучно, и я пошел дальше, потому что я нашел лучший и более простой способ сделать то, что я хотел.

Вместо этого я просто использую строку состояния.

Я не использую Lightline или какой-либо причудливый плагин для строки состояния, как многие люди. Я никогда не находил их такими полезными. Вместо этого я установил свою собственную строку состояния с несколькими простыми вещами, такими как текущий буфер и текущий файл, а также процент файла.

Если вы запустите эту команду…

:set statusline=%p\ %b\ %f

Ваша строка состояния изменится, чтобы показать, насколько далеко вы прокрутили текущий файл в процентах — это %p — текущий номер буфера — это %b — и имя файла — %f. \ должны избегать пробелов между каждым значением.

Чтобы добавить результат функции в строку состояния, заключите его в фигурные скобки…

:set statusline=%{FugitiveHead()}

Для тех, кто использует плагин Fugitive, это напечатает вашу текущую ветку git.

Вы можете добавить что угодно в строку состояния в виде обычного текста, :set statusline=boom будет работать, пробелы должны быть экранированы, а все, что следует за %, будет рассматриваться как специальное значение (см. :h statusline, чтобы просмотреть полный список специальных значений, а также узнать текущее значение ваша строка состояния в любое время просто запустите :set statusline).

Я просто добавил свой список буферов с помощью функции и объединил это с несколькими ярлыками для переключения буферов, и теперь я почти никогда не использую fzf для работы с буферами.

function ListBuffers()
  return join(
    \map(
      \getbufinfo({'buflisted':1}),
      \{ 
          \key, val -> 
            \val.bufnr == buffer_number() ?
              \(len(val.name) > 0 ? 
              \fnamemodify(val.name, ":t") : '[No Name]') . '*' 
            \: (len(val.name) > 0 ?  fnamemodify(val.name, ":t") 
            \: '[No Name]') 
      \}
    \), ' • '
  \)
endfunction
set statusline=%{ListBuffers()}

Это сопоставляет результат функции getbufinfo (которая перечисляет текущие буферы) и для каждого элемента проверяет, является ли это текущим буфером, и добавляет *, если да, и у буфера есть имя, если нет, он показывает [No Name]. Затем он объединяет результат в строку с красивым символом между ними.

Затем я сопоставляю :bnext с <leader>bn, :bprevious с <leader>bp и :bdelete с <leader>bd.

Теперь я могу видеть, сколько у меня буферов, в каком порядке они расположены и в каком я нахожусь. Мне не нужно запускать какую-либо команду, чтобы увидеть их, и мне не нужно думать о том, какое число соответствует какому буферу. .

Таким образом, я никогда не использую fzf для буферов и почти никогда не использую :ls. На самом деле, теперь, когда я использую :ls, я нахожу его очень полезным.