Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vim: Creating parent directories on save

Tags:

vim

mkdir

People also ask

How do I create a parent directory?

How to Create Parent Directories. A parent directory is a directory that is above another directory in the directory tree. To create parent directories, use the -p option. When the -p option is used, the command creates the directory only if it doesn't exist.

Do all directories have parent directories in Linux?

As we all know. Every Unix directories contains special directories- current(.) & parent(..).

How do I change the path of a file in Vim?

You can change the working directory with :cd path/to/new/directory . Or you can enter the full path to the location where you want to save the file with the write command, e.g., :w /var/www/filename .


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

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.


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.


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

I made :saveas! create the directory if missing: https://github.com/henrik/dotfiles/commit/54cc9474b345332cf54cf25b51ddb8a9bd00a0bb


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.