Come posso salvare un file in una directory che non esiste ancora?


35

Supponiamo che io avvii Vim per modificare un nuovo file in una directory non ancora creata:

vim nonExisitingDirectory/newFile.txt

Vim mi mostrerà felicemente un buffer vuoto e posso iniziare a scrivere il mio nuovo file. Ma quando voglio scrivere il file su disco ottengo questo errore:

E212: Can't Open file for writing.

Presumo che ciò avvenga perché la directory non esiste ancora. C'è un modo per forzare Vim a creare la directory per me?

Risposte:


37

Per quanto ne so, non esiste alcuna impostazione o qualcosa del genere per farlo. Ma non tutto è perduto, ovviamente possiamo usare il BufWritePrecomando automatico.
Questo viene eseguito prima che il buffer venga scritto sul disco. Quindi possiamo creare la directory lì se non esiste ancora.

Per esempio:

augroup Mkdir
  autocmd!
  autocmd BufWritePre *
    \ if !isdirectory(expand("<afile>:p:h")) |
        \ call mkdir(expand("<afile>:p:h"), "p") |
    \ endif
augroup END
  • Per prima cosa controlliamo se la directory esiste isdirectory, altrimenti mkdirviene visualizzato un errore.
  • <afile>si riferisce al file che stiamo cercando di salvare; :pè un modificatore per espanderlo al percorso completo (anziché relativo) e :hrimuove l'ultimo componente del percorso (il file).
  • Chiamiamo quindi mkdir()se richiesto. Abbiamo bisogno della pbandiera per mkdir()creare tutte le directory dei genitori (es. Nel caso di nonexistent/more_nonexisting/file.

Naturalmente, puoi anche eseguire il mkdir()comando dalla riga di comando di Vim o associarlo a un keybind, ovvero:

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

Qui ho usato %invece di <afile>, poiché questo è valido solo all'interno di un autocomando (si %riferisce al buffer attualmente attivo, che non funzionerebbe :waad esempio; si <afile>riferisce al nome del file del buffer che attiva l'autocd).

Se lo desideri, puoi anche chiedere una conferma prima di scrivere una directory. Vedi questa domanda per maggiori dettagli: Come posso impedire a Vim di scrivere un file nel comando automatico BufWritePre?


Lo snippet precedente creerà la directory sul primo write ( :w). Se lo desideri, puoi anche creare la directory quando la apri per la prima volta (cioè subito dopo aver digitato vim ...) usando BufNewFileautocmd invece di BufWritePre.


C'è anche un plug-in chiamato auto_mkdir che è effettivamente lo stesso sopra.

In questa pagina c'è uno snippet leggermente espanso che ti chiede anche se vuoi prima creare la directory, che alcuni potrebbero considerare utili. Ha anche convertito il nome file della codifica prima di scriverlo:

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

Non sono sicuro che ciò sia effettivamente necessario, ma se mescoli molto le codifiche e ottieni nomi di file strani, potresti provarlo.


Ho inserito tutto quanto sopra in un auto_mkdir2.vimplugin per una più facile installazione.


3

Posso consigliare un plugin vim di Tim Pope chiamato vim-eunuch che definisce molti comandi estremamente utili quando lavori su UNIX / Linux con Vim (controlla le sue caratteristiche !).

Diciamo che apri vim con vim this/is/a/teste nessuna di queste directory esisteva prima. Basta eseguire :Mkdir!<CR>e vim-eunuco per voi (con crea mkdir -p), in modo da ora è possibile salvare il file con :w<CR>.


2

Utilizzare :Wper creare un file e le relative directory principali:

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

(Aggiungi al tuo vimrc. Basato su una combinazione della risposta di Zyx e delle risposte di Damien Pollet ).


1

Un altro modo con un Van Vim (senza conf o plug-in extra). in Vim:

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

o

$ 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

Spero di contribuire con una versione che si basa sulle risposte di cui sopra per semplificare il flusso di lavoro ancora di più. Sto spesso creando nuovi file all'interno di una vasta gamma di strutture di progetto. Questa modifica mi farà risparmiare una notevole quantità di tempo.

Ci sono due dipendenze a cui posso pensare:

  1. Ho impostato a autochdircausa di come funziona con le <C-x><C-f>mie dichiarazioni di importazione.
  2. il saveas"lascia indietro" (se vuoi) un buffer nascosto alla fine dell'elenco dei buffer. Non sono sicuro che si tratti di un comportamento statale di cui godono tutte le istanze vim / nvim.
  3. Altro FYI: utilizzo NVIM su un 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
    
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.