Vim: Tworzenie katalogów nadrzędnych przy zapisywaniu


122

Jeśli wywołam, vim foo/bar/somefileale foo/barjeszcze nie istnieje, Vim odmówi zapisania.

Wiem, że mógłbym przełączyć się na powłokę lub zrobić :!mkdir foo/bar z Vima, ale jestem leniwy :) Czy jest sposób, aby Vim robił to automatycznie, gdy zapisuje bufor?


13
mkdir -p %:hjest lepsza, ponieważ działa w przypadku zagnieżdżonych nieistniejących ścieżek, nie zgłasza błędu, gdy ścieżka już istnieje i %:hjest pełną ścieżką do bieżącego pliku. Jednak nie wiem, jak wywołać to automatycznie. Zwykle odbywa się to za pomocą automatycznych poleceń, ale BufWritePrezdarzenie wydaje się nie działać tutaj.
— Konrad Rudolph

Zdefiniuj funkcję, która sprawdza, czy plik istnieje i wywołuje wbudowany writei wywołuje system mkdir -pw dirnameprzeciwnym razie, W
— zamapuj

1
Chyba mogę połączyć oba swoje sugestie i alias :waby mkdir -p %:hnastępnie builting:write
— Damien pollet

Odpowiedzi:


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

Zwróć uwagę na warunki: expand("<afile>")!~#'^\w\+:/'uniemożliwi vimowi tworzenie katalogów dla plików takich jak ftp://*i !isdirectoryzapobiegnie kosztownym wywołaniom mkdir.

Aktualizacja : nieznacznie lepsze rozwiązanie, które również sprawdza niepusty typ buforu i używa 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

1
Dzięki, wydaje się znacznie czystszy niż to, co zgaduję, zhakowane :)
— Damien Pollet

11
call mkdir(expand('%:h'), 'p')może być bardziej przenośny.
— Marius Gedminas,

1
@MariusGedminas Chciałbym zobaczyć cały kod z tą zmianą. Czy mógłbyś to gdzieś zamieścić jako odpowiedź / przesłać?
— kikito

@kikito Zobacz moją odpowiedź. Został zredagowany kilka godzin po tym komentarzu.
— ZyX

@Zyx thanks! Skończyło się na tym, że zrobiłem coś nieco krótszego (moja odpowiedź jest obecnie ostatnia), ale wydaje się, że działa to całkiem nieźle.
— kikito

20

W oparciu o sugestie do mojego pytania, oto co otrzymałem:

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

To definiuje :Wpolecenie. Idealnie, chciałbym mieć wszystko :w!, :wq, :wq!, :walletc działają tak samo, ale nie jestem pewien, czy jest to możliwe bez zasadzie reimplementing je wszystkie z funkcji niestandardowych.


2
Wypróbowałem to samo polecenie i za każdym razem, gdy używam :W, mój ekran staje się prawie pusty. Spróbuję usunąć moje poprzednie opcje i przekażę opinię.
— moebius_eye

6

Dodałem to do mojego ~ / .vimrc

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

Jeśli muszę utworzyć katalog, w :mk.którym się znajduję, wpisuję go i zastępuje go ciągiem „! Mkdir -p / ścieżka / do / mój / plik /” i umożliwia mi przejrzenie polecenia przed jego wywołaniem.



3

Ten kod poprosi Cię o utworzenie katalogu za pomocą :wlub po prostu zrób to za pomocą :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

1

Myślę, że udało mi się to zrobić w trzech wierszach, łącząc to, co inni mówią o tej odpowiedzi.

Wydaje się, że to działa:

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

Próbuje utworzyć folder automatycznie podczas zapisywania buforu. Jeśli wydarzy się coś złego (np. Problemy z uprawnieniami), po prostu się zamknie i pozwoli na niepowodzenie zapisu pliku.

Jeśli ktoś zauważy oczywiste wady, napisz komentarz. Nie jestem biegły w skryptach vimscript.

EDYCJA: Uwagi dzięki ZyX

  • To nie zadziała, jeśli twoje foldery mają na sobie spacje (najwyraźniej nie są one poprawnie wyłączone lub coś takiego)
  • Lub jeśli robisz pseudo pliki.
  • Lub jeśli pozyskujesz swój vimrc.
  • Ale synu, to jest krótkie.

1
Nigdy nie używaj %w takich skryptach. Vim nie zamierza uciec żadnych specjalnych symboli, na przykład: jeśli edytujesz plik o nazwie /mnt/windows/Documents and Settings/User/_vimrcskończy się o czterech nowych katalogów: /mnt/windows/Documents, ./and, ./Settingsi ./Settings/User. A tak przy okazji, nie potrzebujesz :executetutaj.
— ZyX

1
Jest system()funkcja dla całkowicie cichych wywołań powłoki, ale nie potrzebujesz obu :executei %:p:h: :silent !mkdir -p %:p:hdziała dokładnie tak, jak napisałeś (chociaż może być potrzebna :redraw!na końcu, w tym przypadku :executejest przydatna), ale lepiej jest jej użyć call system('mkdir -p '.shellescape(expand('%:p:h'))). Używaj :execute '!command' shellescape(arg, 1)(z drugim argumentem shellescape), jeśli zamiast tego musisz użyć grzywki system(). Używaj grzywki, jeśli argument ucieczki zawiera znaki nowej linii.
— ZyX

I nie unikniesz innych problemów, których unikam w moim pierwszym fragmencie kodu: uruchamianie powłoki jeden dodatkowy raz po każdym źródle vimrc (zakładając, że pobierasz aktualizacje vimrc przez wykonanie :source ~/.vimrc) (po to augroupi autocmd!są), odrzucony widok po uruchomieniu powłoki polecenia (do tego służą redraw!), tworzenie katalogów śmieci w przypadku używania pseudo-plików (w pierwszym odcinanym kodzie jest to sprawdzane tylko przez dopasowanie nazwy pliku do wzorca, ale w drugim też sprawdzam &buftype) i bezużyteczne wywołanie powłoki w katalogu case istnieje ( isdirectory()stan).
— ZyX

1
@ZyX Dzięki za twoją opinię. Nie chcę rozwiązywać problemów, których nie mam. Nigdy nie używam znaków specjalnych (tj. Spacji) w moich folderach, więc%: p: h dobrze mi pasuje. Nigdy nie korzystam z vimrc (zamiast tego zabijam i ponownie otwieram vim) i nawet nie wiem, co to są pseudopliki. przerysować! wydaje mi się, że nic mi nie robi. Ale podoba mi się twoja sugestia usunięcia execute, aby wszystko było krótsze. Twoje zdrowie!
— kikito

1
Nie ma znaczenia, czy masz znaki specjalne, czy nie, jest to rzecz, na której powinieneś się przejmować. Jest zbyt wiele problemów z %ekspansją, aby kiedykolwiek sugerować użycie jej komukolwiek. Pseudo pliki są używane w dużej liczbie wtyczek (np. Fugitive lub my aurum), dlatego warto o nie dbać. Pozyskiwanie zasobów vimrc jest również powszechną praktyką. Możesz mieć cokolwiek chcesz w vimrc, po prostu nie sugeruj tego jako odpowiedzi. Użycie :silent! call mkdir(expand('%:p:h'), 'p')wariantu rozwiązuje dwie kwestie, o których wspomniałem, i trzecią, o której nie wspomniałem: !mkdirnie będzie działać w systemie Windows.
— ZyX
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.