Jak zapisać plik w katalogu, który jeszcze nie istnieje?

35

Załóżmy, że uruchomię Vima, aby edytować nowy plik w katalogu, który nie został jeszcze utworzony:

vim nonExisitingDirectory/newFile.txt

Vim chętnie pokaże mi pusty bufor i mogę zacząć pisać mój nowy plik. Ale gdy chcę zapisać plik na dysku, pojawia się ten błąd:

E212: Can't Open file for writing.

Zakładam, że dzieje się tak, ponieważ katalog jeszcze nie istnieje. Czy istnieje sposób, aby zmusić Vima do utworzenia dla mnie katalogu?

DeltaLima
źródło

Odpowiedzi:

37

O ile mi wiadomo, nie ma takiego ustawienia ani czegoś takiego. Ale nie wszystko przepadło, możemy oczywiście użyć polecenia BufWritePreautomatycznego.
Jest to wykonywane przed zapisaniem bufora na dysku. Możemy więc utworzyć tam katalog, jeśli jeszcze nie istnieje.

Na przykład:

augroup Mkdir
  autocmd!
  autocmd BufWritePre *
    \ if !isdirectory(expand("<afile>:p:h")) |
        \ call mkdir(expand("<afile>:p:h"), "p") |
    \ endif
augroup END
  • Najpierw sprawdzamy, czy katalog istnieje isdirectory, w przeciwnym razie mkdirwyświetla błąd.
  • <afile>odnosi się do pliku, który próbujemy zapisać; :pjest modyfikatorem pozwalającym rozwinąć go do pełnej nazwy ścieżki (zamiast względnej) i :husuwa ostatni składnik ścieżki (plik).
  • W mkdir()razie potrzeby dzwonimy . Potrzebujemy pflagi, mkdir()aby wszystkie katalogi rodziców (np. W przypadku nonexistent/more_nonexisting/file.

Możesz oczywiście również uruchomić mkdir()polecenie z wiersza poleceń Vima lub powiązać je ze skrótem klawiszowym, tj .:

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

Tutaj użyłem %zamiast <afile>, ponieważ jest to poprawne tylko w obrębie komendy automatycznej ( %odnosi się do aktualnie aktywnego bufora, który nie działałby :wana przykład; <afile>odnosi się do nazwy pliku bufora, który uruchamia autocmd).

Możesz również poprosić o potwierdzenie przed napisaniem katalogu, jeśli chcesz. Zobacz to pytanie, aby uzyskać więcej informacji: Jak mogę powstrzymać Vima przed zapisaniem pliku w automatycznej komendzie BufWritePre?


Powyższy fragment utworzy katalog przy pierwszym write ( :w). Możesz, jeśli chcesz, również utworzyć katalog przy pierwszym otwarciu (tj. Zaraz po wpisaniu vim ...) za pomocą BufNewFileautocmd zamiast BufWritePre.


Istnieje również wtyczka o nazwie auto_mkdir, która jest faktycznie taka sama jak wyżej.

Na tej stronie znajduje się nieco rozszerzony fragment, który również pyta, czy chcesz najpierw utworzyć katalog, co niektórzy mogą uznać za przydatny. Konwertuje także nazwę pliku kodowania przed jego zapisaniem:

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

Nie jestem jednak pewien, czy jest to faktycznie wymagane, ale jeśli często miksujesz kodowanie i otrzymujesz dziwne nazwy plików, możesz spróbować.


Wszystkie powyższe umieściłem we auto_mkdir2.vimwtyczce, aby ułatwić instalację.

Martin Tournoij
źródło
3

Mogę polecić wtyczkę vima od Tima Pope'a o nazwie vim-eunuch, która definiuje wiele niezwykle przydatnych poleceń podczas pracy w systemie UNIX / Linux z Vimem (sprawdź jego funkcje !).

Załóżmy, że otwierasz vima vim this/is/a/testi żaden z tych katalogów nie istniał wcześniej. Po prostu uruchom :Mkdir!<CR>i vim-eunuch utworzy je dla ciebie (z mkdir -p), abyś mógł teraz zapisać swój plik za pomocą :w<CR>.

cbaumhardt
źródło
2

Użyj, :Waby utworzyć plik i jego katalogi nadrzędne:

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()

(Dodaj do strony vimrc. Na podstawie kombinacji odpowiedzi ZYX za i odpowiedzi Damien pollet za ).

Tom Hale
źródło
1

Innym sposobem jest waniliowy Vim (bez dodatkowej konfiguracji i wtyczek). w Vim:

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

lub

$ 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
xaa
źródło
1

Mam nadzieję, że przekażę wersję, która opiera się na powyższych odpowiedziach, aby jeszcze bardziej usprawnić przepływ pracy. Często tworzę nowe pliki w szerokim zakresie struktur projektu. Ta poprawka pozwoli mi zaoszczędzić sporo czasu.

Są dwie zależności , o których mogę myśleć:

  1. Ustawiłem z autochdirpowodu tego, jak to działa w <C-x><C-f>przypadku moich instrukcji importu.
  2. na saveas„Liście z tyłu” (jak kto woli) ukryty bufor na końcu listy buforowego. Nie jestem pewien, czy jest to zachowanie stanowe, które cieszy wszystkie instancje vim / nvim.
  3. Inne informacje: Używam NVIM na 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
    
Echo Edmunda
źródło