为什么VIM备份文件名不正确?'backupdir'选项未按预期执行

Vic*_*der 14 vim

我正在构建一个自定义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//
Run Code Online (Sandbox Code Playgroud)

双尾斜杠应该导致文件名扩展,其中生成的备份/交换/撤消文件名将是完整路径,%替换每个/,如%home%username%path%to%your%file.ext.

一切都适用于交换和撤销文件,但备份拒绝工作,生成file.ext~没有完整路径扩展的格式的文件名,这意味着当我编辑两个具有相同名称的文件时,第一个文件的备份将丢失(由第二).

有没有人对这个问题有所了解?

Ing*_*kat 11

看起来该'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.
Run Code Online (Sandbox Code Playgroud)

请在vim_dev邮件列表上游说,优先筹集它!


Vic*_*der 6

一段时间已经过去了,似乎这个bug不会很快修复.@DragonRock提出的建议是一个很好的建议,但是错过了一个关键点,即:生成的备份应该是文件当前版本的副本,覆盖之前.所以我使用了自动命令的基本思想,但是BufWritePre在将更改提交到磁盘之前,使用不同的事件将文件的副本复制到备份目标.

这是最终的解决方案,与我们对破坏的功能的期望完全相同(仅适用于Linux):

" === BACKUP SETTINGS ===
" turn backup OFF
" Normally we would want to have it turned on. See bug and workaround below.
" OBS: It's 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
Run Code Online (Sandbox Code Playgroud)

请注意,为清楚起见,自动命令被提取到专用功能.此外,这set nobackup很重要,因为否则会生成重复的备份(一个名称正确,另一个名称不正确).

它将跳过backupskip按预期匹配的备份,支持多个备份目标并附加backupext(文件扩展名,对搜索很有用).

如果当前保存的缓冲区是全新的(或者换句话说,如果您直接使用vim创建新文件),它也会跳过.尝试创建一个空的备份文件是没有意义的,实际上,它会抛出一个错误,因为该文件仍然没有被复制.谢谢@Yahya建议!

silent!指令通过回显备份创建或故障来防止备份操作干扰文件保存操作的正常流程(否则保存本身可能会失败).