Vim: создание родительских каталогов при сохранении

Если я вызываю vim foo/bar/somefile, но foo/bar еще не существует, Vim отказывается сохранять.

Я знаю, что могу переключиться на оболочку или сделать :!mkdir foo/bar у Vim, но я ленивый:) Есть ли способ заставить Vim делать это автоматически, когда он сохраняет буфер?

Ответ 1

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

Ответ 2

Основываясь на предложениях по моему вопросу, вот что я закончил с:

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

Это определяет команду :W. В идеале, я бы хотел, чтобы все теги :w!, :wq, :wq!, :wall и т.д. Работали одинаково, но я не уверен, что это возможно, не переосмысливая их полностью пользовательскими функциями.

Ответ 3

Я добавил это к своему ~/.vimrc

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

Если мне нужно создать каталог, в котором я есть, введите :mk., и он заменит это на "! mkdir -p/path/to/my/file/" и позволяет мне просмотреть команду, прежде чем я ее вызову.

Ответ 5

Этот код предложит вам создать каталог с :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

Ответ 6

Я думаю, мне удалось сделать это в трех строках, объединив то, что другие говорят об этом ответе.

Это похоже на трюк:

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

Он пытается создать папку автоматически при сохранении буфера. Если что-то плохое происходит (например, проблемы с разрешениями), оно просто заткнется и позволит файлу сбой записи.

Если кто-либо видит какие-либо очевидные недостатки, отправьте комментарий. Я не очень разбираюсь в vimscript.

EDIT: Заметки благодаря ZyX

  • Это не будет работать, если в ваших папках есть пробелы (видимо, они не экранированы или что-то не так)
  • Или если вы делаете псевдофайлы.
  • Или, если вы используете ваш vimrc.
  • Но сын, это коротко.