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?

Damien Pollet
fuente
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
ZyX
fuente
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.

Damien Pollet
fuente
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.

Asa Ayers
fuente
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
Tom Hale
fuente
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.
kikito
fuente
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