Vim:在保存时创建父目录


122

如果我调用vim foo/bar/somefilefoo/bar尚不存在,Vim拒绝保存。

我知道我可以切换到shell或:!mkdir foo/bar从Vim进行操作,但是我很懒:)有没有办法让Vim在保存缓冲区时自动执行此操作?


13
mkdir -p %:h更好,因为它适用于嵌套的不存在的路径,当路径已经存在时不会引发错误,并且%:h是当前文件的完整路径。但是,我不知道如何自动调用它。通常,这是通过automcommands完成的,但是该BufWritePre事件似乎在这里不起作用。
康拉德·鲁道夫

定义在检查文件是否存在,并调用内置的函数write,并调用系统mkdir -pdirname,否则,它映射到W...我懒得搜索语法并把它张贴作为答案...对不起
khachik

1
我想我可以结合您的建议和别名:wmkdir -p %:h然后再进行构建:write
Damien Pollet 2010年

Answers:


91
augroup BWCCreateDir
    autocmd!
    autocmd BufWritePre * if expand("<afile>")!~#'^\w\+:/' && !isdirectory(expand("%:h")) | execute "silent! !mkdir -p ".shellescape(expand('%:h'), 1) | redraw! | endif
augroup END

注意以下情况:expand("<afile>")!~#'^\w\+:/'将防止vim为类似文件创建目录,ftp://*!isdirectory防止昂贵的mkdir调用。

更新:更好的解决方案,它还会检查非空buftype并使用mkdir()

function s:MkNonExDir(file, buf)
    if empty(getbufvar(a:buf, '&buftype')) && a:file!~#'\v^\w+\:\/'
        let dir=fnamemodify(a:file, ':h')
        if !isdirectory(dir)
            call mkdir(dir, 'p')
        endif
    endif
endfunction
augroup BWCCreateDir
    autocmd!
    autocmd BufWritePre * :call s:MkNonExDir(expand('<afile>'), +expand('<abuf>'))
augroup END

1
谢谢,似乎比我猜测的要干净的多:)
Damien Pollet

11
call mkdir(expand('%:h'), 'p')可能更便携。
Marius Gedminas,2012年

1
@MariusGedminas我想查看具有此更改的完整代码。您能否将其发布为答案/将其上传到某处?
kikito 2012年

@kikito看看我的回答。该评论在几个小时后被编辑。
ZyX 2012年

@Zyx谢谢!我最终做了一些短一些的事情(我的答案目前是最后一个),但这似乎很好。
kikito 2012年

20

根据对我的问题的建议,以下是我得出的结论:

function WriteCreatingDirs()
    execute ':silent !mkdir -p %:h'
    write
endfunction
command W call WriteCreatingDirs()

这定义了:W命令。理想情况下,我想有所有的:w!:wq:wq!:wall等工作相同,但我不知道是否有可能基本上没有重新实现他们所有的自定义功能。


2
我尝试了相同的命令,每次使用时:W,屏幕几乎都变成空白。我将尝试删除以前的选项并提供反馈。
moebius_eye

6

我将此添加到我的〜/ .vimrc

cnoremap mk. !mkdir -p <c-r>=expand("%:h")<cr>/

如果需要创建目录,请输入,:mk.并将其替换为“!mkdir -p / path / to / my / file /”,并允许我在调用该命令之前先对其进行检查。



3

此代码将提示您使用创建目录:w,或仅使用:w!以下命令创建目录:

augroup vimrc-auto-mkdir
  autocmd!
  autocmd BufWritePre * call s:auto_mkdir(expand('<afile>:p:h'), v:cmdbang)
  function! s:auto_mkdir(dir, force)
    if !isdirectory(a:dir)
          \   && (a:force
          \       || input("'" . a:dir . "' does not exist. Create? [y/N]") =~? '^y\%[es]$')
      call mkdir(iconv(a:dir, &encoding, &termencoding), 'p')
    endif
  endfunction
augroup END

1

我认为我成功地做到了三行,结合了其他人对此答案的看法。

这似乎可以解决问题:

if has("autocmd")
  autocmd BufWritePre * :silent !mkdir -p %:p:h
end

保存缓冲区时,它将尝试自动创建文件夹。如果发生任何不良情况(即权限问题),它将关闭并让文件写入失败。

如果有人发现任何明显的缺陷,请发表评论。我对vimscript不太了解。

编辑:感谢ZyX

  • 如果您的文件夹上有空格(显然它们没有正确转义或其他原因),则此功能将不起作用
  • 或者,如果您正在处理伪文件。
  • 或者,如果您正在采购vimrc。
  • 但是儿子,很短。

1
切勿%在此类脚本中使用。VIM是不会逃避任何特殊符号:例如,如果您正在编辑一个文件名为/mnt/windows/Documents and Settings/User/_vimrc你最终将有四个新的目录:/mnt/windows/Documents./and./Settings./Settings/User。而且,顺便说一句,您不需要:execute在这里。
ZyX

1
有一些system()功能可用于完全无声的shell调用,但是您并不需要:execute%:p:h:都:silent !mkdir -p %:p:h完全按照您编写的内容工作(尽管:redraw!最后可能需要,在这种情况下:execute很方便),但最好使用call system('mkdir -p '.shellescape(expand('%:p:h'))):execute '!command' shellescape(arg, 1)如果必须使用bang而不是,请使用(带有shellescape的第二个参数)system()。如果转义参数包含换行符,请使用刘海。
ZyX

而你不避免其他麻烦我避免在我的第一个代码段:启动shell每次的vimrc采购后,一个额外的时间(假设你的vimrc做更新拉:source ~/.vimrc)(这是augroupautocmd!是),发射后壳报废视图命令(这是什么redraw!),在使用伪文件的情况下创建垃圾目录(在第一个代码片段中,仅通过将文件名与模式匹配来进行检查,但在第二个代码中,我也进行了检查&buftype),并且在情况目录下无用的shell调用存在(isdirectory()条件)。
ZyX

1
@ZyX感谢您的反馈。我不想解决我没有的问题。我从不在文件夹中使用特殊字符(即空格),所以%:p:h对我来说很好。我从不获取vimrc的信息(我杀死并重新打开了vim),我什至不知道什么是伪文件。重绘!似乎对我什么都没做。但是我喜欢您提出的删除执行以缩短所有内容的建议。干杯!
kikito 2012年

1
是否有特殊字符并不重要,这是您应该关心的事情。%扩展有太多问题,无法建议任何人使用它。伪文件用于大量插件(例如,逃犯或我的金光闪闪)中,因此值得关注。对vimrc进行资源配置也是一种常见的做法。您可以在vimrc中拥有任何想要的东西,只是不要建议它作为答案。使用:silent! call mkdir(expand('%:p:h'), 'p')variant解决了我提到的两点,我没有提到的三点:!mkdir在Windows上不起作用。
ZyX
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.