Wie speichere ich eine Datei in einem Verzeichnis, das noch nicht existiert?

35

Angenommen, ich starte Vim, um eine neue Datei in einem Verzeichnis zu bearbeiten, das noch nicht erstellt wurde:

vim nonExisitingDirectory/newFile.txt

Vim zeigt mir gerne einen leeren Puffer und ich kann mit dem Schreiben meiner neuen Datei beginnen. Aber wenn ich die Datei auf die Festplatte schreiben möchte, erhalte ich diesen Fehler:

E212: Can't Open file for writing.

Ich nehme an, das liegt daran, dass das Verzeichnis noch nicht existiert. Gibt es eine Möglichkeit, Vim zu zwingen, das Verzeichnis für mich zu erstellen?

DeltaLima
quelle

Antworten:

37

Soweit mir bekannt ist, gibt es keine oder eine solche Einstellung, um dies zu tun. Aber nicht alles ist verloren, wir können natürlich den BufWritePreAutobefehl verwenden.
Dies wird ausgeführt, bevor der Puffer auf die Festplatte geschrieben wird. So können wir das Verzeichnis dort anlegen, wenn es noch nicht existiert.

Beispielsweise:

augroup Mkdir
  autocmd!
  autocmd BufWritePre *
    \ if !isdirectory(expand("<afile>:p:h")) |
        \ call mkdir(expand("<afile>:p:h"), "p") |
    \ endif
augroup END
  • Wir prüfen zuerst, ob das Verzeichnis mit existiert isdirectory, sonst mkdirgibt es einen Fehler.
  • <afile>verweist auf die Datei, die wir speichern möchten; :pist ein Modifikator zum Erweitern auf den vollständigen Pfadnamen (und nicht auf den relativen Pfadnamen) und zum :hEntfernen der letzten Pfadkomponente (der Datei).
  • Wir rufen mkdir()dann bei Bedarf an. Wir brauchen das pFlag für mkdir()alle Elternverzeichnisse (zB im Fall von nonexistent/more_nonexisting/file.

Sie können den mkdir()Befehl natürlich auch über die Vim-Befehlszeile ausführen oder ihn an eine Tastaturbindung binden.

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

Hier habe ich %stattdessen verwendet <afile>, da dies nur innerhalb eines Autocommands gültig ist ( %bezieht sich auf den aktuell aktiven Puffer, der :wazum Beispiel nicht funktionieren würde ; <afile>bezieht sich auf den Dateinamen des Puffers, der das Autocmd auslöst).

Sie können auch eine Bestätigung anfordern, bevor Sie ein Verzeichnis schreiben, wenn Sie möchten. Weitere Informationen finden Sie in dieser Frage: Wie kann ich verhindern, dass Vim eine Datei im automatischen Befehl BufWritePre schreibt?


Das obige Snippet erstellt das Verzeichnis beim ersten Schreiben ( :w). Wenn Sie möchten , können Sie das Verzeichnis auch erstellen, wenn Sie es zum ersten Mal öffnen (dh direkt nach der Eingabe vim ...), indem BufNewFileSie statt autocmd verwenden BufWritePre.


Es gibt auch ein Plugin namens auto_mkdir, das im Grunde dasselbe ist wie oben.

Auf dieser Seite befindet sich ein etwas erweitertes Snippet, das Sie auch fragt, ob Sie zuerst das Verzeichnis erstellen möchten, was einige als nützlich erachten. Es hat auch den Dateinamen der Kodierung vor dem Schreiben konvertiert:

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

Ich bin mir nicht sicher, ob dies tatsächlich erforderlich ist, aber wenn Sie viele Codierungen mischen und komische Dateinamen erhalten, können Sie es versuchen.


Ich habe all das in ein auto_mkdir2.vimPlugin eingefügt, um die Installation zu vereinfachen.

Martin Tournoij
quelle
3

Ich kann ein vim-Plugin von Tim Pope empfehlen, das vim-eunuch heißt und viele äußerst nützliche Befehle definiert, wenn Sie unter UNIX / Linux mit Vim arbeiten (sehen Sie sich dessen Funktionen an !).

Nehmen wir an, Sie öffnen vim mit vim this/is/a/testund keines dieser Verzeichnisse existierte zuvor. Einfach ausführen :Mkdir!<CR>und vim-eunuch erstellt sie für Sie (mit mkdir -p), damit Sie Ihre Datei jetzt mit speichern können :w<CR>.

cbaumhardt
quelle
2

Verwenden Sie :Wdiese Option , um eine Datei und ihre übergeordneten Verzeichnisse zu erstellen:

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

(Add to your vimrc. Basierend auf einer Kombination aus Zyxs und Damien Pollets Antworten ).

Tom Hale
quelle
1

Ein anderer Weg mit einem Vanille-Vim (ohne zusätzliche conf oder Plugins). in Vim:

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

oder

$ 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
quelle
1

Ich hoffe, eine Version beizutragen, die auf den obigen Antworten aufbaut, um den Workflow noch weiter zu optimieren. Ich erstelle häufig neue Dateien innerhalb einer Vielzahl von Projektstrukturen. Diese Optimierung spart mir viel Zeit.

Es gibt zwei Abhängigkeiten , die ich mir vorstellen kann:

  1. Ich habe für meine Import-Anweisungen festgelegt, autochdirwie es funktioniert <C-x><C-f>.
  2. das saveas"hinterlässt" (wenn man so will) einen versteckten Puffer am Ende der Pufferliste. Ich bin nicht sicher, ob dies ein Zustandsverhalten ist, das allen vim / nvim-Instanzen gefällt.
  3. Sonstiges: Ich verwende NVIM auf einem 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
    
Edmunds Echo
quelle