Как сохранить файл в каталоге, который еще не существует?

35

Предположим, я запускаю Vim для редактирования нового файла в каталоге, который еще не создан:

vim nonExisitingDirectory/newFile.txt

Vim с радостью покажет мне пустой буфер, и я могу начать писать свой новый файл. Но когда я хочу записать файл на диск, я получаю эту ошибку:

E212: Can't Open file for writing.

Я предполагаю, что это потому, что каталог еще не существует. Есть ли способ заставить Vim создать каталог для меня?

DeltaLima
источник

Ответы:

37

Насколько я знаю, нет настройки или что-то подобное для этого. Но не все потеряно, мы, конечно, можем использовать BufWritePreавтокоманду.
Это выполняется до того, как буфер будет записан на диск. Таким образом, мы можем создать каталог там, если он еще не существует.

Например:

augroup Mkdir
  autocmd!
  autocmd BufWritePre *
    \ if !isdirectory(expand("<afile>:p:h")) |
        \ call mkdir(expand("<afile>:p:h"), "p") |
    \ endif
augroup END
  • Сначала мы проверяем, существует ли каталог с isdirectory, иначе mkdirвыдает ошибку.
  • <afile>ссылается на файл, который мы пытаемся сохранить; :pявляется модификатором, расширяющим его до полного пути (а не относительного), и :hудаляет последний компонент пути (файл).
  • Затем мы позвоним, mkdir()если потребуется. Нам нужен pфлаг для mkdir()создания всех родительских каталогов (т. Е. В случае nonexistent/more_nonexisting/file.

Конечно, вы также можете запустить mkdir()команду из командной строки Vim или связать ее с привязкой клавиш, то есть:

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

Здесь я использовал %вместо <afile>, так как это действительно только из автокоманды ( %относится к текущему активному буферу, с которым, например, не будет работать :wa; <afile>относится к имени файла буфера, который запускает autocmd).

Вы также можете запросить подтверждение, прежде чем писать каталог, если хотите. Смотрите этот вопрос для более подробной информации: Как я могу остановить Vim от записи файла в автокоманде BufWritePre?


Приведенный выше фрагмент создаст каталог при первой записи ( :w). При желании вы также можете создать каталог при первом его открытии (т. Е. Сразу после ввода текста vim ...), используя BufNewFileвместо него autocmd BufWritePre.


Существует также плагин с именем auto_mkdir, который практически не отличается от описанного выше.

На этой странице есть слегка расширенный фрагмент, который также спрашивает вас, хотите ли вы сначала создать каталог, что некоторые могут посчитать полезным. Он также преобразует имя файла кодировки перед записью:

call mkdir(iconv(expand("%:p:h"), &encoding, &termencoding), 'p')

Хотя я не уверен, требуется ли это на самом деле, но если вы много смешиваете кодировки и получаете странные имена файлов, вы можете попробовать это.


Я поместил все вышеперечисленное в auto_mkdir2.vimплагин для облегчения установки.

Мартин Турной
источник
3

Я могу порекомендовать плагин vim от Tim Pope под названием vim-eunuch, который определяет множество чрезвычайно полезных команд при работе с UNIX / Linux с Vim (ознакомьтесь с его возможностями !).

Допустим, вы открываете vim, vim this/is/a/testи ни один из этих каталогов не существовал ранее. Просто запустите :Mkdir!<CR>и vim-eunuch создаст их для вас (с помощью mkdir -p), так что теперь вы можете сохранить свой файл с помощью :w<CR>.

cbaumhardt
источник
2

Используйте :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 в и ответы Дэмиена POLLET в ).

Том Хейл
источник
1

Еще один способ с ванильным Vim (без дополнительных конф или плагинов). в 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
хаа
источник
1

Я надеюсь предоставить версию, основанную на приведенных выше ответах, чтобы еще больше упростить рабочий процесс. Я часто создаю новые файлы в широком спектре структур проекта. Этот твик сэкономит мне много времени.

Есть две зависимости, о которых я могу думать:

  1. Я установил autochdirиз-за того, как это работает <C-x><C-f>для моих операторов импорта.
  2. что saveas«оставляет позади» (если будет) скрытый буфер в конце списка буферов. Я не уверен, что такое поведение состояния, которым пользуются все экземпляры vim / nvim.
  3. Другое к вашему сведению: я использую NVIM на Mac OS

    " 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
    
Эхо Эдмунда
источник