Vim: creación de directorios principales al guardar


122

Si invoco vim foo/bar/somefilepero foo/baraún no existo, Vim se niega a guardar.

Sé que podría cambiar a un shell o hacerlo :!mkdir foo/bardesde Vim, pero soy vago :) ¿Hay alguna manera de hacer que Vim lo haga automáticamente cuando guarda el búfer?


13
mkdir -p %:hes mejor porque funciona para rutas anidadas no existentes, no genera un error cuando la ruta ya existe y %:hes la ruta completa del archivo actual. Sin embargo, no sé cómo invocar esto automáticamente. Normalmente, esto se hace con comandos automáticos, pero el BufWritePreevento no parece funcionar aquí.
— Konrad Rudolph

Definir una función que comprueba si existe el archivo y llama a la orden interna writey llama al sistema mkdir -pde dirnameotra manera, asignarlo a W... soy demasiado perezoso para buscar la sintaxis y la publicación, como una respuesta ... Lo siento
— Jachik

1
Supongo que podría combinar sus sugerencias y alias :wpara mkdir -p %:hseguir el edificio:write
— Damien Pollet

Respuestas:


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

Tenga en cuenta las condiciones: expand("<afile>")!~#'^\w\+:/'evitará que vim cree directorios para archivos como ftp://*y !isdirectoryevitará llamadas costosas a mkdir.

Actualización : solución ligeramente mejor que también comprueba el tipo de búfer no vacío y utiliza 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
Gracias, parece mucho más limpio de lo que supongo: pirateado :)
— Damien Pollet

11
call mkdir(expand('%:h'), 'p')podría ser más portátil.
— Marius Gedminas

1
@MariusGedminas Me gustaría ver el código completo con ese cambio. ¿Podrías publicarlo como respuesta / subirlo a algún lugar?
— kikito

@kikito Mira mi respuesta. Fue editado unas horas después de ese comentario.
— ZyX

@Zyx gracias! Terminé haciendo algo un poco más corto (mi respuesta es actualmente la última) pero parece funcionar bien.
— kikito

20

Según las sugerencias de mi pregunta, esto es lo que terminé con:

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

Esto define el :Wcomando. Idealmente, me gustaría tener todos :w!, :wq, :wq!, :walletc funcionar de la misma, pero no estoy seguro si es posible sin reimplementar básicamente a todos con funciones personalizadas.


2
Probé este mismo comando y cada vez que lo uso :W, mi pantalla se vuelve casi en blanco. Intentaré eliminar mis opciones anteriores y dar mi opinión.
— moebius_eye

6

Agregué esto a mi ~ / .vimrc

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

Si necesito crear el directorio en el que estoy, escribo :mk.y lo reemplaza con "! Mkdir -p / ruta / a / mi / archivo /" y me permite revisar el comando antes de invocarlo.



3

Este código le pedirá que cree el directorio con :w, o simplemente lo haga con :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

Creo que logré hacer esto en tres líneas, combinando lo que otros dicen en esta respuesta.

Esto parece funcionar:

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

Intenta crear la carpeta automáticamente al guardar un búfer. Si sucede algo malo (es decir, problemas de permisos), simplemente se cerrará y dejará que falle la escritura del archivo.

Si alguien ve defectos obvios, publique un comentario. No estoy muy versado en vimscript.

EDITAR: Notas gracias a ZyX

  • Esto no funcionará si sus carpetas tienen espacios (aparentemente no se escapan correctamente o algo así)
  • O si está haciendo pseudo archivos.
  • O si está obteniendo su vimrc.
  • Pero hijo, es corto.

1
Nunca lo use %en tales scripts. Vim no se va a escapar símbolos especiales: por ejemplo, si está editando un archivo con el nombre /mnt/windows/Documents and Settings/User/_vimrcque va a terminar con cuatro nuevos directorios: /mnt/windows/Documents, ./and, ./Settingsy ./Settings/User. Y, por cierto, :executeaquí no es necesario .
— ZyX

1
Hay una system()función para llamadas de shell completamente silenciosas, pero no necesita ambas :executey %:p:h: :silent !mkdir -p %:p:hfunciona exactamente como lo que ha escrito (aunque puede que lo necesite :redraw!al final, en este caso :executees útil), pero es mejor usarlo call system('mkdir -p '.shellescape(expand('%:p:h'))). Hacer uso :execute '!command' shellescape(arg, 1)(con el segundo argumento de shellescape) si se tiene que utilizar en lugar de las explosiones system(). Utilice bangs si el argumento de escape contiene nuevas líneas.
— ZyX

Y no evita otros problemas que estoy evitando en mi primer fragmento de código: iniciar shell una vez más después de cada fuente de vimrc (suponiendo que obtenga actualizaciones de vimrc al hacerlo :source ~/.vimrc) (para esto es augroupy autocmd!son), vista desechada después de iniciar shell comandos (para eso es redraw!), crear directorios de basura en caso de usar pseudo-archivos (en el primer código recortado, se verifica solo haciendo coincidir el nombre del archivo con un patrón, pero en el segundo también verifico &buftype) y una llamada de shell inútil en el directorio de casos existe ( isdirectory()condición).
— ZyX

1
@ZyX Gracias por tus comentarios. No quiero resolver problemas que no tengo. Nunca uso caracteres especiales (es decir, espacios) en mis carpetas, por lo que%: p: h me funciona bien. Nunca obtengo vimrc (mato y vuelvo a abrir vim) y ni siquiera sé qué son los pseudofiles. redibujar! no parece hacerme nada en absoluto. Pero me gusta tu sugerencia de eliminar ejecutar para que todo sea más corto. ¡Salud!
— kikito

1
No importa si tienes o no caracteres especiales, es lo que debería preocuparte. Hay demasiados problemas con la %expansión como para sugerir su uso a nadie. Los pseudoarchivos se utilizan en una gran cantidad de complementos (por ejemplo, fugitive o my aurum), por lo que vale la pena cuidarlos. Dotar de recursos a vimrc también es una práctica común. Puede tener lo que quiera en el vimrc, pero no lo sugiera como respuesta. El uso de la :silent! call mkdir(expand('%:p:h'), 'p')variante resuelve dos de los puntos que mencioné y el tercero que no mencioné: !mkdirno va a funcionar en Windows.
— ZyX
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.