¿Cómo puedo hacer que Vim lea automáticamente un archivo mientras no tiene foco?

29

Estoy usando VIm para todo tipo de cosas (o gVim en este caso), incluida la salida de monitoreo escrita en un archivo; Utilizo autoreadpara hacer que Vim vuelva a leer el archivo, lo que hace cada vez que le cambio el foco del teclado.

¿Hay alguna forma de hacer que Vim actualice el búfer incluso si no cambio el foco del teclado? He intentado configurar checktimepero no parece tener ningún efecto mientras el foco del teclado está en otra parte.

La salida que estoy monitoreando está reemplazando el archivo de salida por completo; y no estoy mirando a tail -fél. Hay otras opciones, como canalizar una nueva instancia cada vez, o canalizar lesso algo así, pero sería genial si se pudiera hacer con VIm.

falstro
fuente
@Carpetsmoker, ¿qué tal el CursorHoldevento? Si Vim no tiene foco, debería activarse cada n segundos.
muru
1
@muru No, CursorHoldse ejecuta solo una vez, esto se documenta explícitamente como: "no dispara cada 'tiempo de actualización' ms si deja Vim para hacer un café. :)"
Martin Tournoij
1
Quité el gvim etiqueta de nuevo, espero que está bien ;-) Como yo lo veo, esta pregunta es no realmente sobre gVim, como el cambio de enfoque es sólo un caso en el que los cheques Vim si se cambia el archivo (hay un montón, ver mi respuesta para más detalles). La mayoría, si no todas, las formas de mejorar esto funcionarán bien tanto en Vim como en gVim.
Martin Tournoij
@Carpetsmoker ah, tenía la impresión de que gVim revisaba regularmente mientras tenía el foco del teclado (por lo que es una pregunta de gVim), pero parece que me equivoqué. Gracias por aclarar eso.
falstro

Respuestas:

20

Actualización 2015-06-25 :

  • He descartado el método "shell", ya que era demasiado disfuncional. Se detuvo el modo de inserción y dejó procesos zombie. Mira el historial de revisiones de esta publicación si realmente quieres verlo de todos modos.
  • He hecho un complemento de esto: auto_autoread.vim . Por el momento, es efectivamente el mismo que el código a continuación, pero recomendaría que use el complemento ya que es probable que reciba actualizaciones.

¿Qué autoreadhacer?

Para responder a esta pregunta, primero debemos entender qué hace la autoreadopción y, lo que es más importante, qué no hace.

Lamentablemente :help 'autoread' no tiene mucha información sobre esto, solo dice "se ha detectado que un archivo ha sido cambiado fuera de Vim" . ¿Cómo detecta Vim que se ha cambiado un archivo? En ciertas acciones, Vim verifica el tiempo de modificación del archivo.

Cuando:

  • :checktime se usa
  • se ingresa un buffer;
  • :diffupdate se usa
  • :e se emite para un archivo que ya tiene un búfer;
  • ejecutando un comando externo con !;
  • volver al primer plano ( ^Z, fg, sólo si la cáscara tiene control de trabajo);

para gVim, esto también se hace cuando:

  • cerrar el menú "clic derecho" (ya sea seleccionando algo o simplemente cerrándolo);
  • se cambia el enfoque (esto es lo que ya notó);
  • cerrar el cuadro de diálogo del explorador de archivos que aparece si usa "archivo -> abrir", "archivo -> guardar como" en el menú (así como en otros lugares).

Reuní esta información desde la fuente de Vim mediante la localización de todas las llamadas a las buf_check_timestamp(), check_timestamps()funciones y lugares en los que need_check_timestampsse establece en TRUE.

Puede que me haya perdido algunos eventos, pero la clave para recordar es que Vim solo verifica si el archivo se modifica en un conjunto muy limitado de circunstancias . Ciertamente no "sondea" el archivo en busca de cambios cada n segundos, que es básicamente lo que buscas.

Entonces, para su propósito, set autoreadno es suficiente.

Usando Python

Esto programa un hilo de Python para que se ejecute en segundo plano, se ejecutará :checktimecada n segundos. Si autoreadestá habilitado , esto volverá a cargar el búfer del disco, de lo contrario, solo advertirá.

Esto requiere que Vim tenga +pythono +python3en :version. Debería funcionar en todas las plataformas (incluido Windows).

fun! AutoreadPython()
python << EOF
import time, vim
try: import thread
except ImportError: import _thread as thread # Py3

def autoread():
    vim.command('checktime')  # Run the 'checktime' command
    vim.command('redraw')     # Actually update the display

def autoread_loop():
    while True:
        time.sleep(1)
        autoread()

thread.start_new_thread(autoread_loop, ())
EOF
endfun

Puede comenzar esto usando :call AutoreadPython(); por supuesto, puedes hacer esto en un autocmd; por ejemplo:

autocmd *.c call AutoreadPython()

Epílogo

En realidad, hay más métodos, por ejemplo, podría usar una herramienta como entrPython inotifyo el gaminmódulo para monitorear un archivo en busca de cambios, :checktimetambién verifica todos los buffers si no tiene ningún argumento, esto podría mejorarse al verificar solo un solo buffer o un cierto archivo
Sin embargo, esta respuesta ya es bastante larga :-) Este método debería (¡ojalá!) Funcionar bien para la mayoría de los escenarios, o debería ser fácilmente adaptable a su escenario.

PD. También intenté usar Ruby, pero desafortunadamente los hilos de Ruby (usando Thread) no se ejecutan en segundo plano como lo hace Python, por lo que no pude hacer que esto funcionara (¿quizás hay otra forma, sin embargo?)

Martin Tournoij
fuente
2

Hice un pequeño complemento vim-autoread que usa tail -fpara actualizar el búfer en segundo plano de forma asincrónica. Obviamente, esto necesita la función de trabajo de Vim Versión 8.

Use :AutoReadpara encenderlo y :AutoRead!apagarlo.

Christian Brabandt
fuente
¡Una versión compatible con NeoVim sería genial!
Andrew
@ AndrewMacFie No veo, por qué esto no funcionaría en Neovim.
Christian Brabandt
la falta de soporte de trabajos Vim 8 en NeoVim pensé?
Andrew
@AndrewMacFie oh, eso probablemente sea cierto. Como no uso neovim, no puedo hacerlo compatible con NeoVim. Sin embargo, un RP sería bienvenido :)
Christian Brabandt
bastante justo:)
Andrew
1

En Neovim, podría usar el siguiente comando que abrirá un búfer de terminal que ejecuta el comando de cola.

:enew | call termopen('tail --follow=name --retry /path/to/file.log')

Esto continuará funcionando incluso si el archivo se elimina y se vuelve a crear.

O agregue lo siguiente a su $MYVIMRC

" :Tail /path/to/file
function! Tail(file)
  enew
  call termopen('tail --follow=name --retry ' . fnameescape(a:file))
endfunction
command! -nargs=1 Tail call Tail(<f-args>)
Brett Y
fuente
1

de esta respuesta (refiriéndose a una respuesta de PhanHaiQuang y un comentario de flukus )

Uno puede ejecutar este oneliner desde ex (dentro de vim) cuando sea necesario (o poner cada comando en vimrc, para cuando se abren los archivos de registro).

:set autoread | au CursorHold * checktime | call feedkeys("lh")

Explicación:
- autoread : lee el archivo cuando se cambia desde el exterior (pero no funciona por sí solo, no hay un temporizador interno o algo así. Solo leerá el archivo cuando vim realice una acción, como un comando en ex :!
- CursorHold * checktime : cuando el usuario no mueve el cursor durante el tiempo especificado en 'updatetime' (que es 4000 milisegundos por defecto) se ejecuta checktime, que verifica los cambios desde fuera del archivo
- llame a las teclas de alimentación ("lh") : el cursor se mueve una vez, hacia la derecha y hacia la izquierda, y luego no pasa nada (... lo que significa que se activa CursorHold, lo que significa que tenemos un bucle )

eli
fuente