Vim: Creating parent directories on save

VimMkdir

Vim Problem Overview


If I invoke vim foo/bar/somefile but foo/bar don't already exist, Vim refuses to save.

I know I could switch to a shell or do :!mkdir foo/bar from Vim but I'm lazy :) Is there a way to make Vim do that automatically when it saves the buffer?

Vim Solutions


Solution 1 - Vim

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

Note the conditions: expand("<afile>")!~#'^\w\+:/' will prevent vim from creating directories for files like ftp://* and !isdirectory will prevent expensive mkdir call.

Update: sligtly better solution that also checks for non-empty buftype and uses 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

Solution 2 - Vim

Based on the suggestions to my question, here's what I ended up with:

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

This defines the :W command. Ideally, I'd like to have all of :w!, :wq, :wq!, :wall etc work the same, but I'm not sure if it's possible without basically reimplementing them all with custom functions.

Solution 3 - Vim

I added this to my ~/.vimrc

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

If I need to create the directory I'm in I type :mk. and it replaces that with "!mkdir -p /path/to/my/file/" and allows me to review the command before I invoke it.

Solution 4 - Vim

This code will prompt you to create the directory with :w, or just do it with :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

Solution 5 - Vim

Solution 6 - Vim

I think I managed to do this in three lines, combining what others are saying on this answer.

This seems to do the trick:

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

It attempts to create the folder automatically when saving a buffer. If anything bad happens (i.e. permission issues) it will just shut up and let the file write fail.

If anyone sees any obvious flaws, please post a comment. I'm not very versed in vimscript.

EDIT: Notes thanks to ZyX

  • This will not work if your folders have spaces on them (apparently they are not properly escaped or something)
  • Or if you are doing pseudo files.
  • Or if you are sourcing your vimrc.
  • But son, it is short.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDamien PolletView Question on Stackoverflow
Solution 1 - VimZyXView Answer on Stackoverflow
Solution 2 - VimDamien PolletView Answer on Stackoverflow
Solution 3 - VimAsa AyersView Answer on Stackoverflow
Solution 4 - VimTom HaleView Answer on Stackoverflow
Solution 5 - VimHenrik NView Answer on Stackoverflow
Solution 6 - VimkikitoView Answer on Stackoverflow