Tengo un autocmd para los archivos TeX y Markdown para guardar el archivo automáticamente. Nada inusual:
autocmd CursorHold *.tex,*.md w
Sin embargo, a medida que aumentaron las configuraciones personalizadas para estos archivos, los dividí en ftplugin/tex.vim
y ftplugin/markdown.vim
:
" ftplugin/tex.vim
autocmd CursorHold *.tex w
" ftplugin/markdown.vim
autocmd CursorHold *.md w
Ahora, estos archivos se obtienen solo para los archivos apropiados, por lo que la coincidencia de patrones es redundante. Aparentemente, autocmd
s puede ser local en el búfer. De :h autocmd-buffer-local
:
Buffer-local autocommands are attached to a specific buffer. They are useful
if the buffer does not have a name and when the name does not match a specific
pattern. But it also means they must be explicitly added to each buffer.
Instead of a pattern buffer-local autocommands use one of these forms:
<buffer> current buffer
<buffer=99> buffer number 99
<buffer=abuf> using <abuf> (only when executing autocommands)
<abuf>
Eso parece estar destinado a tal uso. Ahora, ambos ftplugin/tex.vim
y ftplugin/markdown.vim
pueden tener:
autocmd CursorHold <buffer> w
No estoy realmente preocupado por la extensión real, siempre y cuando el tipo de archivo es correcta, así que esto me ahorra tener que preocuparse por *.md
y *.markdown
y cualquier otro extensiones son válidos para Markdown.
¿Es este uso <buffer>
correcto? ¿Hay alguna dificultad que deba tener en cuenta? ¿Se complicarán las cosas si borro un búfer y abro otro (espero que los números no choquen, pero ...)?
up
(abreviatura de:update
) sería mejor quew
en su autocmd (evite escrituras innecesarias).w
falló. Repetidamente.:up
no hace nada en ese caso. :)Respuestas:
Creo que es correcto, pero solo necesita envolverlo dentro de un grupo de aug, y borrar el último, para asegurarse de que el autocmd no se duplicará cada vez que ejecute un comando que recargue el mismo búfer.
Como explicó, el patrón especial le
<buffer>
permite confiar en el mecanismo de detección de tipo de archivo incorporado, implementado dentro del archivo$VIMRUNTIME/filetype.vim
.En este archivo, puede encontrar los autocmds integrados de Vim que son responsables de establecer el tipo de archivo correcto para cualquier búfer dado. Por ejemplo, para rebajas:
Dentro de su complemento de tipo de archivo, puede copiar los mismos patrones para cada autocmd que instale. Por ejemplo, para guardar automáticamente el búfer cuando el cursor no se ha movido durante unos segundos:
Pero
<buffer>
es mucho menos detallado:Además, si algún día otra extensión es válida y
$VIMRUNTIME/filetype.vim
se actualiza para incluirla, sus autocmds no serán informados. Y tendrá que actualizar todos sus patrones dentro de sus complementos de tipo de archivo.No estoy seguro, pero no creo que Vim pueda reutilizar el número de búfer de un búfer borrado. No pude encontrar la sección relevante de la ayuda, pero encontré este párrafo en vim.wikia.com :
Además, como explicó @ Tumbler41 , cuando limpia un búfer, se eliminan sus autocmds. De
:h autocmd-buflocal
:Si desea comprobarlo usted mismo, puede hacerlo aumentando el nivel de verbosidad de Vim a 6. Puede hacerlo temporalmente, solo para un comando, utilizando el
:verbose
modificador. Entonces, dentro de su búfer de reducción, puede ejecutar:Luego, si revisas los mensajes de Vim:
Deberías ver una línea como esta:
¿Dónde
42
estaba el número de su búfer de descuento?Hay 3 situaciones que consideraría como escollos y que involucran el patrón especial
<buffer>
. En dos de ellos,<buffer>
puede ser un problema, en el otro es una solución.Trampa 1
Primero, debe tener cuidado con la forma en que borra los grupos de sus autocmds de búfer local. Debe estar familiarizado con este fragmento:
Por lo tanto, podría tener la tentación de usarlo para sus autocmds locales de búfer, sin modificar, como este:
Pero esto tendrá un efecto no deseado. La primera vez que cargue un búfer de
A
reducción, llamémoslo, su autocmd se instalará correctamente. Luego, cuando vuelva a cargarA
, el autocmd se eliminará (debido aautocmd!
) y se volverá a instalar. Entonces, el augroup evitará correctamente la duplicación del autocmd.Ahora, suponga que carga un segundo búfer de reducción, llamémoslo
B
, en una segunda ventana. TODOS los autocmds del augroup se borrarán: ese es el autocmd deA
y el deB
. Luego, se instalará un solo autocmd paraB
.Por lo tanto, cuando realice algún cambio
B
y espere unos segundos paraCursorHold
que se dispare, se guardará automáticamente. Pero si vuelveA
y hace lo mismo, el búfer no se guardará. Esto se debe a que la última vez que cargó un búfer de reducción, hubo un desequilibrio entre lo que eliminó y lo que agregó. Eliminaste más de lo que agregaste.La solución es no eliminar TODOS los autocmds, sino solo los del búfer actual, pasando el patrón especial
<buffer>
a:autocmd!
:Tenga en cuenta que puede reemplazar
CursorHold
con una estrella para que coincida con cualquier evento en la línea que elimine autocmds:De esta manera, no tiene que especificar todos los eventos a los que están escuchando sus autocmds cuando desea borrar el augroup.
Pitfall 2
Hay otra trampa, pero esta vez
<buffer>
no es el problema, es la solución.Cuando incluye una opción local en un complemento de tipo de archivo, probablemente lo haga así:
Esto funcionará como se espera para las opciones locales de búfer, pero no siempre para las locales de ventana. Para ilustrar el problema, puede intentar el siguiente experimento. Crea el archivo
~/.vim/after/ftdetect/potion.vim
, y dentro de él escribe:Este archivo configurará automáticamente el tipo
potion
de archivo para cualquier archivo cuya extensión sea.pn
. No necesita envolverlo dentro de un augroup porque, para este tipo particular de archivo, Vim lo hará automáticamente (ver:h ftdetect
).Si los directorios intermedios no existen en su sistema, puede crearlos.
A continuación, cree el complemento de tipo de archivo
~/.vim/after/ftplugin/potion.vim
y, dentro, escriba:De manera predeterminada, en un
potion
archivo, esta configuración hará que los caracteres de tabulación se muestren como^I
y el final de las líneas como$
.Ahora, crea un mínimo
vimrc
;/tmp/vimrc
escritura interior :... para habilitar los complementos de tipo de archivo.
Además, cree un archivo de pociones
/tmp/pn.pn
, y un archivo aleatorio/tmp/file
. En el archivo de pociones, escribe algo:En el archivo aleatorio, escriba la ruta al archivo de la poción
/tmp/pn.pn
:Ahora, inicie Vim con un mínimo de inicializaciones, solo obtenga
vimrc
y abra ambos archivos en ventanas verticales:Debería ver 2 ventanas verticales. El archivo de pociones a la izquierda muestra el final de las líneas con signos de dólar, el archivo aleatorio a la derecha no los muestra en absoluto.
Centra la atención en el archivo aleatorio y presiona
gf
para mostrar el archivo de pociones cuya ruta está debajo del cursor. Ahora verá el mismo búfer de pociones en la ventana gráfica correcta, pero esta vez, el final de las líneas no se muestra con signos de dólar. Y si escribe:setlocal list?
, Vim debería responder connolist
:Toda la cadena de eventos:
... no ocurrió, porque el primero de ellos,
BufRead
no ocurrió cuando presionastegf
. El búfer ya estaba cargado.Puede parecer inesperado, porque cuando agregó
setlocal list
dentro de su plugin de tipo de archivo de poción, puede haber pensado que habilitaría la'list'
opción en cualquier ventana que muestre un búfer de poción.El problema no es específico de este nuevo tipo de
potion
archivo. También puedes experimentarlo con unmarkdown
archivo.Tampoco es específico de la
'list'
opción. Se puede experimentar con otras configuraciones de ventana local, como'conceallevel'
,'foldmethod'
,'foldexpr'
,'foldtitle'
, ...Tampoco es específico del
gf
comando. Puede experimentarlo con otros comandos que pueden cambiar el búfer que se muestra en la ventana actual: marca global,C-o
(retroceder en el jumplista local de la ventana):b {buffer_number}
, ...Para resumir, las opciones locales de la ventana se establecerán correctamente, si y solo si:
BufRead
tendrá que ser despedido):split
(en este caso, debe heredar las opciones locales de la ventana donde se ejecutó el comando)De lo contrario, las opciones locales de la ventana pueden no estar configuradas correctamente.
Una posible solución sería establecerlos no directamente desde un complemento de tipo de archivo, sino desde un autocmd instalado en este último, que escucharía
BufWinEnter
. Este evento debe activarse cada vez que se muestra un búfer en una ventana.Entonces, por ejemplo, en lugar de escribir esto:
Escribirías esto:
Y aquí, encuentras de nuevo el patrón especial
<buffer>
.Trampa 3
Si cambia el tipo de archivo de su búfer, los autocmds permanecerán. Si desea eliminarlos, debe configurar
b:undo_ftplugin
(ver:h undo_ftplugin
) e incluir este comando en él:Sin embargo, no intente eliminar el augroup en sí, porque aún podría haber algunos buffers de rebajas que tienen autocmds en su interior.
FWIW, este es el fragmento de UltiSnips que estoy usando para configurar
b:undo_ftplugin
:Y aquí hay un ejemplo de valor que tengo en
~/.vim/after/ftplugin/awk.vim
:Como nota al margen, entiendo por qué hizo la pregunta, porque cuando busqué todas las líneas donde
<buffer>
se utilizó el patrón especial en los archivos predeterminados de Vim:Solo encontré 9 coincidencias (puede encontrar más o menos, estoy usando Vim versión 8.0, con parches hasta
134
). Y entre las 9 coincidencias, 7 están en la documentación, solo 2 son de origen. Debería encontrarlos en $ VIMRUNTIME / syntax / dircolors.vim :No sé si puede causar un problema, pero no están dentro de un augroup, lo que significa que cada vez que se vuelve a cargar un búfer cuyo tipo de archivo es
dircolors
(sucede si edita un archivo llamado.dircolors
,.dir_colors
o cuyos extremos trayectoria con/etc/DIR_COLORS
), el complemento de sintaxis agregará un nuevo autocmd local de búfer.Puedes verificarlo así:
El último comando debería mostrar esto:
Ahora, vuelva a cargar el búfer y vuelva a preguntar cuáles son los autocmds locales del búfer para el búfer actual:
Esta vez, verás:
Después de cada carga de los archivos,
s:reset_colors()
ys:preview_color('.')
será llamado una vez adicional, cada vez que uno de los eventosCursorHold
,CursorHoldI
,CursorMoved
,CursorMovedI
es despedido.Probablemente no sea un gran problema, porque incluso después de volver a cargar un
dircolors
archivo varias veces, no vi una desaceleración notable o un comportamiento inesperado de Vim.Si es un problema para usted, puede contactar al responsable del complemento de sintaxis, pero mientras tanto, si desea evitar la duplicación de autocmds, puede crear su propio complemento de sintaxis para los
dircolors
archivos, utilizando el archivo~/.vim/syntax/dircolors.vim
. Dentro, importaría el contenido del complemento de sintaxis original:Luego, en este último, simplemente envolvería los autocmds dentro de un augroup que borraría. Entonces, reemplazarías estas líneas:
... con estos:
Tenga en cuenta que si creó su
dircolors
complemento de sintaxis con el archivo~/.vim/after/syntax/dircolors.vim
, no funcionaría, porque el complemento de sintaxis predeterminado se obtendría antes. Al usarlo~/.vim/syntax/dircolors.vim
, su complemento de sintaxis se generará antes que el predeterminado, y establecerá la variable local del búferb:current_syntax
, lo que evitará que se obtenga el complemento de sintaxis predeterminado porque contiene esta protección:La regla general parece ser: use los directorios
~/.vim/ftplugin
y~/.vim/syntax
para crear un complemento de tipo de archivo / sintaxis personalizado y evitar que se obtenga el siguiente complemento (para el mismo tipo de archivo) en la ruta de tiempo de ejecución (incluidos los predeterminados). Y use~/.vim/after/ftplugin
,~/.vim/after/syntax
no para evitar que se obtengan otros complementos, sino solo para tener la última palabra sobre el valor de algunas configuraciones.fuente
autocmd!
conautocmd! CursorHold <buffer>
enaugroup
bloques es un problema particularmente crítico, y debería haberse destacado por adelantado. No obstante ... esta es una inversión descaradamente sorprendente de tiempo, esfuerzo y lágrimas sangrientas.