Vim: Erstellen von übergeordneten Verzeichnissen beim Speichern

122

Wenn ich aufrufe, vim foo/bar/somefileaber foo/barnoch nicht existiere, weigert sich Vim zu speichern.

Ich weiß, dass ich :!mkdir foo/barvon Vim zu einer Shell wechseln oder etwas tun könnte, aber ich bin faul :) Gibt es eine Möglichkeit, Vim dazu zu bringen, dies automatisch zu tun, wenn der Puffer gespeichert wird?

Damien Pollet
quelle
13
mkdir -p %:hist besser, weil es für verschachtelte nicht vorhandene Pfade funktioniert, keinen Fehler auslöst, wenn der Pfad bereits vorhanden ist, und %:hder vollständige Pfad der aktuellen Datei ist. Ich weiß jedoch nicht, wie ich dies automatisch aufrufen soll. Normalerweise geschieht dies mit automatischen Befehlen, aber das BufWritePreEreignis scheint hier nicht zu funktionieren.
Konrad Rudolph
Definieren Sie eine Funktion , die prüft , ob die Datei vorhanden ist und ruft die builtin writeund fordert das System mkdir -pauf dirnameandere Weise, wo es zu W... ich bin zu faul für die Syntax zu suchen und es als eine Antwort zu schreiben ... Sorry
Khachik
1
Ich denke, ich könnte sowohl Ihre Vorschläge als auch Ihren Pseudonym kombinieren :w, mkdir -p %:hgefolgt vom Bau:write
Damien Pollet

Antworten:

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

Beachten Sie die Bedingungen: expand("<afile>")!~#'^\w\+:/'Verhindert, dass vim Verzeichnisse für Dateien wie erstellt, ftp://*und !isdirectoryverhindert teure mkdir-Aufrufe.

Update : Etwas bessere Lösung, die auch nach nicht leeren Buftypen sucht und Folgendes verwendet 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
ZyX
quelle
1
Danke, scheint viel sauberer als das, was ich gehackt habe :)
Damien Pollet
11
call mkdir(expand('%:h'), 'p')könnte tragbarer sein.
Marius Gedminas
1
@MariusGedminas Ich möchte den vollständigen Code mit dieser Änderung sehen. Könnten Sie es bitte als Antwort posten / irgendwo hochladen?
Kikito
@kikito Siehe meine Antwort. Es wurde einige Stunden nach diesem Kommentar bearbeitet.
ZyX
@ Zyx danke! Am Ende habe ich etwas kürzeres gemacht (meine Antwort ist derzeit die letzte), aber es scheint den Trick gut zu machen.
Kikito
20

Basierend auf den Vorschlägen zu meiner Frage habe ich Folgendes erhalten:

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

Dies definiert den :WBefehl. Im Idealfall würde Ich mag alle haben :w!, :wq, :wq!, :wallusw. die gleiche Arbeit, aber ich bin nicht sicher , ob es ohne grundsätzlich Neuimplementierung sie alle mit benutzerdefinierten Funktionen möglich ist.

Damien Pollet
quelle
2
Ich habe den gleichen Befehl ausprobiert und jedes Mal :W, wenn ich ihn benutze , wird mein Bildschirm fast leer. Ich werde versuchen, meine vorherigen Optionen zu entfernen und Feedback zu geben.
moebius_eye
6

Ich habe dies zu meinem ~ / .vimrc hinzugefügt

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

Wenn ich das Verzeichnis erstellen muss, in dem ich mich :mk.befinde, tippe ich es durch "! Mkdir -p / path / to / my / file /" und kann den Befehl überprüfen, bevor ich ihn aufrufe.

Asa Ayers
quelle
3

Dieser Code fordert Sie auf, das Verzeichnis mit :woder einfach zu erstellen :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
Tom Hale
quelle
1

Ich glaube, ich habe es geschafft, dies in drei Zeilen zu tun und zu kombinieren, was andere zu dieser Antwort sagen.

Dies scheint den Trick zu tun:

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

Es wird versucht, den Ordner beim Speichern eines Puffers automatisch zu erstellen. Wenn etwas Schlimmes passiert (dh Berechtigungsprobleme), wird es einfach heruntergefahren und das Schreiben der Datei schlägt fehl.

Wenn jemand offensichtliche Mängel sieht, schreibe bitte einen Kommentar. Ich bin nicht sehr versiert in Vimscript.

EDIT: Notizen dank ZyX

  • Dies funktioniert nicht, wenn Ihre Ordner Leerzeichen enthalten (anscheinend sind sie nicht ordnungsgemäß maskiert oder so).
  • Oder wenn Sie Pseudodateien machen.
  • Oder wenn Sie Ihr vimrc beziehen.
  • Aber mein Sohn, es ist kurz.
Kikito
quelle
1
Verwenden Sie niemals %in solchen Skripten. Vim wird keine besonderen Symbole entkommen: zum Beispiel, wenn Sie eine Datei mit dem Namen bearbeiten /mnt/windows/Documents and Settings/User/_vimrcwerden vier neue Verzeichnisse am Ende mit: /mnt/windows/Documents, ./and, ./Settingsund ./Settings/User. Und das brauchen Sie übrigens :executehier nicht.
ZyX
1
Es gibt eine system()Funktion für völlig stille Shell-Aufrufe, aber Sie benötigen nicht beide :executeund %:p:h: :silent !mkdir -p %:p:hfunktioniert genau so, wie Sie es geschrieben haben (obwohl Sie es :redraw!am Ende benötigen , ist es in diesem Fall :executepraktisch), aber es ist besser zu verwenden call system('mkdir -p '.shellescape(expand('%:p:h'))). Verwenden Sie :execute '!command' shellescape(arg, 1)(mit dem zweiten Argument für shellescape), wenn Sie stattdessen Pony verwenden müssen system(). Verwenden Sie Pony, wenn das Escape-Argument Zeilenumbrüche enthält.
ZyX
Und Sie vermeiden keine anderen Probleme, die ich in meinem ersten Code-Snippet vermeide: Starten der Shell ein weiteres Mal nach jedem vimrc-Sourcing (vorausgesetzt, Sie ziehen vimrc-Updates ein, indem Sie dies tun :source ~/.vimrc) (dies ist augroupund wozu autocmd!), verschrottete Ansicht nach dem Starten der Shell Befehle (das ist es, wofür redraw!), das Erstellen von Garbage-Verzeichnissen bei Verwendung von Pseudodateien (im ersten abgeschnittenen Code wird dies überprüft, indem nur der Dateiname mit einem Muster abgeglichen wird, aber im zweiten überprüfe ich auch &buftype) und nutzloser Shell-Aufruf im case-Verzeichnis existiert ( isdirectory()Bedingung).
ZyX
1
@ZyX Danke für dein Feedback. Ich möchte keine Probleme lösen, die ich nicht habe. Ich verwende niemals spezielle Zeichen (dh Leerzeichen) in meinen Ordnern, daher ist%: p: h für mich in Ordnung. Ich beziehe nie vimrc (ich töte und öffne stattdessen vim) und ich weiß nicht einmal, was Pseudodateien sind. neu zeichnen! scheint mir überhaupt nichts anzutun. Aber ich mag Ihren Vorschlag, Execute zu entfernen, um alles kürzer zu machen. Prost!
Kikito
1
Es spielt keine Rolle, ob Sie Sonderzeichen haben oder nicht, es ist das, was Sie interessieren sollten. Es gibt zu viele Probleme mit der %Erweiterung, als dass man sie jemals jemandem empfehlen könnte. Pseudodateien werden in einer Vielzahl von Plugins verwendet (z. B. Flüchtling oder mein Aurum), daher lohnt es sich, sich darum zu kümmern. Die Beschaffung von vimrc ist ebenfalls eine gängige Praxis. Sie können alles im vimrc haben, was Sie wollen, schlagen Sie es einfach nicht als Antwort vor. Die Verwendung der :silent! call mkdir(expand('%:p:h'), 'p')Variante löst zwei der Punkte, die ich erwähnt habe, und den dritten, den ich nicht erwähnt habe: !mkdirWird unter Windows nicht funktionieren.
ZyX