¿Puede vim monitorear cambios en tiempo real en un archivo?

104

Mi pregunta es similar a cómo monitorear un archivo de texto en tiempo real, pero quiero hacerlo en vim. Sé que puedo leer un archivo de uso de tail -f sample.xmlarchivo abierto , y cuando se escribe contenido nuevo en el archivo, también escribirá el contenido nuevo en mi pantalla. ¿Puedo hacer que vim complete automáticamente los nuevos datos cuando se actualiza un archivo?

Patricio
fuente

Respuestas:

101

Puede :set autoreadhacerlo para que vim lea el archivo cuando cambie. Sin embargo (dependiendo de su plataforma), debe darle un enfoque.

De la ayuda:

Cuando se detecta que un archivo se ha cambiado fuera de Vim y no se ha cambiado dentro de Vim, léalo de nuevo automáticamente. Cuando el archivo se ha eliminado, esto no se hace.

Pedro
fuente
5
¡Gracias por la pista! Esto parece bastante prometedor, pero no funciona en mi sistema :( Estoy usando Mac10.6.2 iTerm con vim versión 7.2.303 compilada con MacVim. ¿Algún comentario adicional que pueda probar?
Patrick
erm, eso es bastante extraño. ¿Está utilizando la interfaz gráfica de usuario de macvim o la versión de terminal? me funciona con macvim gui descargado precompilado. (Sin embargo, tengo que hacer clic en la aplicación para enfocarla, como mencioné).
Peter
1
Estaba probando en la terminal, después de usar gvim (MacVim GUI), ¡la función comenzó a funcionar! Sin embargo, como mencionaste, necesito enfocar gvim para actualizar el contenido. ¿Tienes algún truco para actualizarlo incluso sin enfocar? Gracias por su ayuda de nuevo.
Patrick
3
No conozco una solución para eso, desafortunadamente. Me sorprendería que vim pudiera hacerlo sin el cambio de enfoque; requeriría que vim sondeara el sistema de archivos para ver cuándo cambia. Creo que necesitarías un complemento para eso.
Peter
2
@Peter Hice un complemento de este tipo hace un tiempo. Vea también esta pregunta y mi respuesta . para obtener más detalles sobre cómo autoreadfunciona y sus limitaciones.
Martin Tournoij
63

No sé automáticamente, pero puede escribir:

:e!

para recargar el archivo

dimba
fuente
Aunque este enfoque no actualiza automáticamente el contenido, sí muestra el contenido actualizado. ¡Gracias por tu respuesta!
Patrick
31

Pon lo siguiente en tu .vimrc:

"verifique una vez después de 4 segundos de inactividad en modo normal
establecer lectura automática                                                                                                                                                                                    
au CursorHold * checktime                                                                                                                                                                       
Phan Hai Quang
fuente
¡Excelente! Funciona bien, incluso con una advertencia si ha cambiado ese archivo desde la última recarga.
zoujyjs
1
La primera respuesta no funcionó para mí, ¡pero esto funciona! :-)
Ionică Bizău
4
El "cada 4 segundos" no es cierto. Esto solo se comprobará una vez después de 4 segundos de inactividad en modo normal. Entonces, si no hace nada en otro búfer durante mucho tiempo, no se actualizará, pero lo hará si mueve el cursor y espera 4 segundos. Otra opción es llamar manualmente a ": checktime" para actualizar (después de configurar la lectura automática). Desafortunadamente, no parece haber ningún tipo de soporte de encuestas en vim, por lo que no hay una respuesta verdadera a la pregunta de los OP.
David Ljung Madison Stellar
1
Acabo de encontrarme con esto. Si cambia el tiempo de verificación para llamar a una función personalizada y agrega "call feedkeys (" lh ")" al final de la función, se activará cada 4 segundos.
flukus
@DavidLjungMadison tienes razón, voy a editar la publicación para evitar este error
Phan Hai Quang
9

como dijo @flukus en un comentario a una respuesta anterior , puede call feedkeys["lh"](mueve el cursor hacia la derecha y hacia la izquierda, lo que normalmente no hace daño al ver un archivo de registro)

Entonces, si combina el resto de la respuesta , tiene un delineador único que puede ejecutar desde ex (dentro de vim) cuando sea necesario:

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


(si desea saltar (casi) al final del archivo, simplemente use "G" en lugar de "lh" con las teclas de alimentación)

Explicación:
- lectura automática : 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 haga 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 busca cambios desde fuera del archivo
- llame a feedkeys ("lh") : el cursor se mueve una vez, a la derecha y atrás a la izquierda. y luego no pasa nada (... lo que significa que CursorHold se activa, lo que significa que tenemos un bucle )

Además puedes :set syntax=logtalkcolorear el tronco

Para detener el desplazamiento cuando se usa call feedkeys("G"), ejecute :set noautoread; ahora vim le dirá que el archivo fue cambiado y preguntará si uno quiere leer los cambios o no)

(¿Tiene esto algún efecto secundario?)

Editar: Veo un efecto secundario: si uno usa "G" es la tecla de alimentación, ¿se desplazará hacia abajo en cada búfer abierto actualmente? Por lo tanto, no es posible trabajar en el búfer izquierdo de una ventana de splittet mientras que el búfer derecho se desplaza hacia abajo en un archivo de registro automáticamente

eli
fuente
4

Pegue esto en su .vimrc y debería funcionar como un jefe. (Tomado de: http://vim.wikia.com/wiki/Have_Vim_check_automatically_if_the_file_has_changed_externally )

" Function to Watch for changes if buffer changed on disk
function! WatchForChanges(bufname, ...)
  " Figure out which options are in effect
  if a:bufname == '*'
    let id = 'WatchForChanges'.'AnyBuffer'
    " If you try to do checktime *, you'll get E93: More than one match for * is given
    let bufspec = ''
  else
    if bufnr(a:bufname) == -1
      echoerr "Buffer " . a:bufname . " doesn't exist"
      return
    end
    let id = 'WatchForChanges'.bufnr(a:bufname)
    let bufspec = a:bufname
  end
  if len(a:000) == 0
    let options = {}
  else
    if type(a:1) == type({})
      let options = a:1
    else
      echoerr "Argument must be a Dict"
    end
  end
  let autoread    = has_key(options, 'autoread')    ? options['autoread']    : 0
  let toggle      = has_key(options, 'toggle')      ? options['toggle']      : 0
  let disable     = has_key(options, 'disable')     ? options['disable']     : 0
  let more_events = has_key(options, 'more_events') ? options['more_events'] : 1
  let while_in_this_buffer_only = has_key(options, 'while_in_this_buffer_only') ? options['while_in_this_buffer_only'] : 0
  if while_in_this_buffer_only
    let event_bufspec = a:bufname
  else
    let event_bufspec = '*'
  end
  let reg_saved = @"
  "let autoread_saved = &autoread
  let msg = "\n"
  " Check to see if the autocommand already exists
  redir @"
    silent! exec 'au '.id
  redir END
  let l:defined = (@" !~ 'E216: No such group or event:')
  " If not yet defined...
  if !l:defined
    if l:autoread
      let msg = msg . 'Autoread enabled - '
      if a:bufname == '*'
        set autoread
      else
        setlocal autoread
      end
    end
    silent! exec 'augroup '.id
      if a:bufname != '*'
        "exec "au BufDelete    ".a:bufname . " :silent! au! ".id . " | silent! augroup! ".id
        "exec "au BufDelete    ".a:bufname . " :echomsg 'Removing autocommands for ".id."' | au! ".id . " | augroup! ".id
        exec "au BufDelete    ".a:bufname . " execute 'au! ".id."' | execute 'augroup! ".id."'"
      end
        exec "au BufEnter     ".event_bufspec . " :checktime ".bufspec
        exec "au CursorHold   ".event_bufspec . " :checktime ".bufspec
        exec "au CursorHoldI  ".event_bufspec . " :checktime ".bufspec
      " The following events might slow things down so we provide a way to disable them...
      " vim docs warn:
      "   Careful: Don't do anything that the user does
      "   not expect or that is slow.
      if more_events
        exec "au CursorMoved  ".event_bufspec . " :checktime ".bufspec
        exec "au CursorMovedI ".event_bufspec . " :checktime ".bufspec
      end
    augroup END
    let msg = msg . 'Now watching ' . bufspec . ' for external updates...'
  end
  " If they want to disable it, or it is defined and they want to toggle it,
  if l:disable || (l:toggle && l:defined)
    if l:autoread
      let msg = msg . 'Autoread disabled - '
      if a:bufname == '*'
        set noautoread
      else
        setlocal noautoread
      end
    end
    " Using an autogroup allows us to remove it easily with the following
    " command. If we do not use an autogroup, we cannot remove this
    " single :checktime command
    " augroup! checkforupdates
    silent! exec 'au! '.id
    silent! exec 'augroup! '.id
    let msg = msg . 'No longer watching ' . bufspec . ' for external updates.'
  elseif l:defined
    let msg = msg . 'Already watching ' . bufspec . ' for external updates'
  end
  echo msg
  let @"=reg_saved
endfunction

let autoreadargs={'autoread':1}
execute WatchForChanges("*",autoreadargs)
moeabdol
fuente
1
Esta es la respuesta preferida para abordar las deficiencias de lectura automática del terminal.
mcanfield
3
@mcanfield No, no lo es, ya que esto todavía no "busca cambios". Usted todavía necesita tener Vim activa y es todavía sondeo (no ver) en un conjunto limitado de eventos. CursorHoldse ejecuta una vez . Entonces, si te vas y tomas un café, o estás haciendo algo en otra ventana, no se actualizará.
Martin Tournoij
4
Ese script también se incluye como un complemento de Vim: vim-autoread .
stephen.hanson
1
@ stephen.hanson ¡Gracias por el enlace, ese complemento funciona bien para mí!
Tropilio
3

Tail Bundle debería hacer lo que quieras. Tenga en cuenta que no lo he usado yo mismo.

Alok Singhal
fuente
2

Si unix + neovim

:term tail -f <filename>

Obviamente, esto no funcionará para todos, pero así es como lo hago.

Jeb
fuente
0

VIM le advertirá cuando un archivo se haya actualizado para que no sobrescriba los cambios que se han realizado desde que lo abrió. En ese momento, le indicará que vuelva a cargar el archivo.

prestomación
fuente
1
Gracias por su respuesta, pero vim no me advirtió cuando se cambió el archivo en mi sistema :(
Patrick