假设我启动Vim来编辑尚未创建的目录中的新文件:文件。但是,当我要将文件写入磁盘时,出现以下错误:

vim nonExisitingDirectory/newFile.txt


我想这是因为该目录尚不存在。有没有办法强迫Vim为我创建目录?

#1 楼

据我所知,目前尚无设置或类似设置。但是并不是所有的丢失,我们当然可以使用BufWritePre自动命令。

这是在将缓冲区写入磁盘之前执行的。因此,我们可以在尚不存在的目录中创建目录。

例如:

augroup Mkdir
  autocmd!
  autocmd BufWritePre * call mkdir(expand("<afile>:p:h"), "p")
augroup END




<afile>指的是我们要保存的文件; :p是一个修饰符,用于将其扩展为完整路径名(而不是相对路径),并且:h删除了最后一个路径组件(文件)。
然后如果需要,我们调用mkdir()。我们需要pmkdir()标志来建立所有父目录(例如nonexistent/more_nonexisting/file),这也确保了如果目录已经存在也不会出错。

您当然可以,还可以从Vim命令行运行mkdir()命令,或将其绑定到按键绑定,例如:一个自动命令(%是指当前活动的缓冲区,例如,不适用于<afile>%是指触发autocmd的缓冲区的文件名)。

您也可以在请求之前进行确认根据需要编写目录。有关更多详细信息,请参见此问题:如何阻止Vim在BufWritePre自动命令中写入文件?


以上代码段将在第一次写入时创建目录(:wa)。如果需要,您还可以在初次打开目录时(即在键入<afile>之后)使用:w autocmd而不是vim ...创建目录。


也有一个名为的插件auto_mkdir与上面的命令实际上相同。有用。在编写之前,它还转换了编码的文件名:

nnoremap <Leader>m :call mkdir(expand("%:p:h"), "p")<CR>


虽然我不确定是否确实需要这样做,但是如果您混合使用多种编码并获取奇怪的文件名,则可以尝试。


我将以上所有内容都放在了BufNewFile插件中,以便于安装。

#2 楼

我可以推荐Tim Pope的vim插件vim-eunuch,它在使用Vim的UNIX / Linux上工作时定义了许多非常有用的命令(请查看其功能!)。

假设您使用以下命令打开vim: vim this/is/a/test并且以前没有这些目录。只需运行:Mkdir!<CR>,vim-eunuch就会为您创建它们(使用mkdir -p),因此您现在可以使用:w<CR>保存文件。

#3 楼

香草Vim的另一种方式(无需额外的conf或插件)。在Vim中:

:!mkdir -p /folder/you/want/
:w  #save file




$ vim /folder/you/want/myfile.conf
$ ctrl+z # switch to the terminal then create the folders
$ mkdir -p /folder/you/want/
$ fg # return to Vim
$ :w  #save file


#4 楼

使用:W创建文件及其父目录:

function! s:WriteCreatingDirs()
  let l:file=expand("%")
  if empty(getbufvar(bufname("%"), '&buftype')) && l:file !~# '\v^\w+\:\/'
    let dir=fnamemodify(l:file, ':h')
    if !isdirectory(dir)
      call mkdir(dir, 'p')
    endif
  endif
  write
endfunction
command! W call s:WriteCreatingDirs()


(添加到您的vimrc中。基于Zyx的答案和Damien Pollet的答案)。 >

#5 楼

我希望提供一个基于上述答案的版本,以进一步简化工作流程。我经常在各种项目结构中创建新文件。这种调整将为我节省大量时间。

我可以想到两个依赖项:


我设置了autochdir,因为它对于我的import语句与<C-x><C-f>一起工作。
saveas在缓冲区列表的末尾“向后隐藏”(如果愿意的话)一个隐藏的缓冲区。我不确定这是否是所有vim / nvim实例都喜欢的状态行为。

其他仅供参考:我在Mac OS上使用NVIM

" Auto magically Mkdir
" ====================

autocmd BufWritePre * call MkDir()

function! MkDir()
   if !isdirectory(expand("<afile>:p:h"))
      let confirmation=confirm("Create a new directory?", "&Yes\n&No")
      if confirmation == 1
         call mkdir(expand("<afile>:p:h"), "p")
         lcd %:p:h
         saveas %:t
         echom "Created a new directory:" expand("<afile>:p:h")
         let buf_del = bufnr("$")
         exe "bd" . buf_del
      endif
      redraw
   endif
endfunction

" Conditionaly create the parent directory when writing to disk
" <afile> refers to the file we are saving
" :p is a modifier that expands to full filename
" :h is a modifier that removes the file from full filename
" :t is a modifier that generates the filename with extension
" "p" is the flag that will create all the parent directories