¿Cómo guardo un archivo en un directorio que aún no existe?


35

Supongamos que inicio Vim para editar un nuevo archivo en un directorio que aún no se ha creado:

vim nonExisitingDirectory/newFile.txt

Vim felizmente me mostrará un búfer vacío y puedo comenzar a escribir mi nuevo archivo. Pero cuando quiero escribir el archivo en el disco me sale este error:

E212: Can't Open file for writing.

Supongo que esto se debe a que el directorio aún no existe. ¿Hay alguna manera de obligar a Vim a crear el directorio para mí?

Respuestas:


37

Por lo que sé, no hay una configuración o algo así para hacer esto. Pero no todo está perdido, por supuesto, podemos usar el BufWritePreautocomando.
Esto se ejecuta antes de que el búfer se escriba en el disco. Entonces podemos crear el directorio allí si aún no existe.

Por ejemplo:

augroup Mkdir
  autocmd!
  autocmd BufWritePre *
    \ if !isdirectory(expand("<afile>:p:h")) |
        \ call mkdir(expand("<afile>:p:h"), "p") |
    \ endif
augroup END
  • Primero verificamos si el directorio existe isdirectory, de lo contrario mkdirda un error.
  • <afile>se refiere al archivo que estamos tratando de guardar; :pes un modificador para expandirlo al nombre de ruta completo (en lugar de relativo), y :helimina el último componente de ruta (el archivo).
  • Luego llamamos mkdir()si es necesario. Necesitamos la pbandera para mkdir()hacer todos los directorios de los padres (es decir, en el caso de nonexistent/more_nonexisting/file.

Por supuesto, también puede ejecutar el mkdir()comando desde la línea de comandos de Vim, o vincularlo a una combinación de teclas, es decir:

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

Aquí utilicé en %lugar de <afile>, ya que eso solo es válido desde un autocomando (se %refiere al búfer actualmente activo, que no funcionaría, :wapor ejemplo; se <afile>refiere al nombre de archivo del búfer que activa el autocmd).

También puede solicitar una confirmación antes de escribir un directorio si lo desea. Consulte esta pregunta para obtener más detalles: ¿Cómo puedo evitar que Vim escriba un archivo en el comando automático BufWritePre?


El fragmento anterior creará el directorio en la primera escritura ( :w). Si lo desea, también puede crear el directorio cuando lo abra por primera vez (es decir, justo después de escribir vim ...) utilizando el BufNewFileautocmd en lugar de BufWritePre.


También hay un complemento llamado auto_mkdir que es efectivamente el mismo que el anterior.

En esta página hay un fragmento ligeramente expandido que también le pregunta si desea crear el directorio primero, lo que algunos pueden considerar útil. También ha convertido el nombre de archivo de la codificación antes de escribirlo:

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

Sin embargo, no estoy seguro de si esto es realmente necesario, pero si mezclas muchas codificaciones y obtienes nombres de archivo extraños, puedes intentarlo.


Puse todo lo anterior en un auto_mkdir2.vimcomplemento para facilitar la instalación.


3

Puedo recomendar un complemento vim de Tim Pope llamado vim-eunuch que define muchos comandos extremadamente útiles cuando trabajas en UNIX / Linux con Vim (¡mira sus características !).

Digamos que abre vim con vim this/is/a/testy ninguno de estos directorios existía antes. Simplemente ejecute :Mkdir!<CR>y vim-eunuch los crea para usted (con mkdir -p), para que ahora pueda guardar su archivo con :w<CR>.


2

Use :Wpara crear un archivo y sus directorios principales:

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

(Añadir a tu vimrc. Sobre la base de una combinación de la respuesta de Zyx y respuestas de Damien Pollet ).


1

Otra forma con un Vim de vainilla (sin conf o complementos adicionales). en 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

Espero contribuir con una versión que se base en las respuestas anteriores para agilizar el flujo de trabajo. A menudo estoy creando nuevos archivos dentro de una amplia gama de estructuras de proyectos. Este ajuste me ahorrará una gran cantidad de tiempo.

Hay dos dependencias en las que puedo pensar:

  1. Lo configuré autochdirpor cómo funciona <C-x><C-f>para mis declaraciones de importación.
  2. el saveas"deja atrás" (si lo desea) un búfer oculto al final de la lista de búferes. No estoy seguro de si ese es el comportamiento de estado que disfrutan todas las instancias vim / nvim.
  3. Otro FYI: uso NVIM en 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
    
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.