Почему имена файлов резервных копий VIM не верны? Опция "backupdir" не работает как ожидалось

Я создаю пользовательский vimrc для улучшения своего рабочего процесса, и мне очень понравилась идея установки централизованного каталога для сохранения всех файлов резервного копирования, свопинга и отмены, например:

" === BACKUP SETTINGS ===
" turn backup ON
set backup
set backupdir=~/.vim/backup//

" === SWAP FILES ===
" turn swap files ON
set swapfile
set directory=~/.vim/swap//

" === UNDO FILES ===
" turn undofiles ON
set undofile
set undodir=~/.vim/undo//

Предполагается, что двойная конечная косая черта приведет к расширению имени файла, где итоговое имя файла резервной копии /swap/undo будет полным путем, а % заменяет каждый /, что-то вроде %home%username%path%to%your%file.ext.

Все отлично работает для файлов свопинга и отмены, но резервные копии отказываются работать, генерируя имена файлов в формате file.ext~ без полного расширения пути, а это значит, что при редактировании двух файлов с тем же именем резервное копирование первого (перезаписывается вторым).

Кто-нибудь знает об этой проблеме?

Ответ 1

Кажется, что параметр 'backupdir' не поддерживает перевод полного абсолютного пути в имя файла (используя % для разделителей путей), например 'directory' и 'undodir' do. По крайней мере, ничто не упоминается в :help 'backupdir'.

Поскольку это противоречиво, и я вижу ваш вариант использования, вы должны отправить запрос в список рассылки vim_dev. На самом деле уже есть такой патч в очереди (veeery long) (:help todo.txt):

7   The 'directory' option supports changing path separators to "%" to make
    file names unique, also support this for 'backupdir'. (Mikolaj Machowski)
    Patch by Christian Brabandt, 2010 Oct 21.

Пожалуйста, любезно пригласите список рассылки vim_dev, чтобы повысить приоритет!

Ответ 2

Некоторое время уже прошло, и кажется, что эта ошибка не будет исправлена ​​в ближайшее время. Рекомендация, представленная @DragonRock, является приятной, но не учитывает ключевой момент, который заключается в следующем: созданная резервная копия должна быть копией текущей версии файла, перезапись ПЕРЕД. Поэтому я использовал основную идею автокоманды, но с другим событием BufWritePre, чтобы сделать копию файла в целевые места резервного копирования, прежде чем совершать изменения на диске.

Это окончательное решение, которое имеет точно такое же поведение, какое мы ожидаем от сломанной функции (работает только в Linux):

" === BACKUP SETTINGS ===
" turn backup OFF
" Normally we would want to have it turned on. See bug and workaround below.
" OBS: It a known-bug that backupdir is not supporting
" the correct double slash filename expansion
" see: https://code.google.com/p/vim/issues/detail?id=179
set nobackup

" set a centralized backup directory
set backupdir=~/.vim/backup//

" This is the workaround for the backup filename expansion problem.
autocmd BufWritePre * :call SaveBackups()

function! SaveBackups()
  if expand('%:p') =~ &backupskip | return | endif

  " If this is a newly created file, don't try to create a backup
  if !filereadable(@%) | return | endif

  for l:backupdir in split(&backupdir, ',')
    :call SaveBackup(l:backupdir)
  endfor
endfunction

function! SaveBackup(backupdir)
  let l:filename = expand('%:p')
  if a:backupdir =~ '//$'
      let l:backup = escape(substitute(l:filename, '/', '%', 'g')  . &backupext, '%')
  else
      let l:backup = escape(expand('%') . &backupext, '%')
  endif

  let l:backup_path = a:backupdir . l:backup
  :silent! execute '!cp ' . resolve(l:filename) . ' ' . l:backup_path
endfunction

Обратите внимание, что автоматическая команда была выделена для выделенной функции для ясности. Также важно set nobackup, потому что в противном случае он будет генерировать дублированные резервные копии (один с правильным именем и один с неправильным именем).

Он будет пропускать резервные копии, которые соответствуют backupskip, как ожидалось, поддерживать несколько мест назначения резервного копирования и добавлять backupext (расширение файла, полезное для поиска).

Он также пропустит, если текущий сохраненный буфер является совершенно новым (или, другими словами, если вы создаете новый файл, используя vim напрямую). Не было бы смысла пытаться создать пустой файл резервной копии, и, на самом деле, он выдавал бы ошибку, потому что файл все еще не копируется. Спасибо @Yahya за предложение

Команда silent! не позволяет операции резервного копирования нарушить нормальный поток операции сохранения файла, повторяя создание резервной копии или сбои (иначе само спасение может потерпеть неудачу).

Ответ 3

Я добавляю этот ответ, потому что считаю, что это действительно расстраивает.

Это может быть обход, пока Vim не добавит функцию перевода пути к backupdir. То, что я сделал, добавляет следующую строку в мой .vimrc:

autocmd BufWritePost * :execute ':w! ' ."$HOME/.vim/backups/" . substitute(escape(substitute(expand('%:p'), "/", "%", "g"), "%"), ' ', '\\ ', 'g')

В принципе, каждый раз, когда вы сохраняете файл, он также сохраняет копию в $HOME/.vim/backups.

Ответ 4

В дополнение к ответу Виктора Шредера я предлагаю вместо этого использовать этот автокоманду:

autocmd BufWritePre * if filereadable(@%) | :call SaveBackups() | endif

Если это не так, оно не будет работать в том случае, если вы открываете новый файл непосредственно с помощью vim. И не имеет смысла сохранять пустую резервную копию...