Peut vim surveiller les modifications en temps réel d'un fichier


104

Ma question est similaire à celle-ci: comment surveiller un fichier texte en temps réel, mais je veux le faire dans vim. Je sais que je peux lire un fichier d'utilisation de tail -f sample.xmlfichier ouvert , et lorsqu'un nouveau contenu est écrit dans le fichier, il écrira également le nouveau contenu sur mon écran. Puis-je demander à vim de remplir automatiquement les nouvelles données lorsqu'un fichier est mis à jour?

Réponses:


101

Vous pouvez :set autoreadafin que vim lise le fichier lorsqu'il change. Cependant (en fonction de votre plateforme), vous devez lui donner du focus.

De l'aide:

Lorsqu'un fichier a été détecté comme ayant été modifié en dehors de Vim et qu'il n'a pas été modifié à l'intérieur de Vim, relisez-le automatiquement. Lorsque le fichier a été supprimé, cela n'est pas fait.


5
Merci pour l'indice! Cela semble assez prometteur, mais cela ne fonctionne pas sur mon système: (J'utilise l'iTerm Mac10.6.2 avec la version vim 7.2.303 compilée avec MacVim. Un commentaire supplémentaire que je peux essayer?
Patrick

euh, c'est assez bizarre. utilisez-vous l'interface graphique macvim ou la version du terminal? cela fonctionne pour moi avec macvim gui téléchargé précompilé. (Je dois cependant cliquer sur l'application pour lui donner le focus, comme je l'ai mentionné.)
Peter

1
Je testais dans le terminal, après avoir utilisé gvim (interface graphique MacVim), la fonction a commencé à fonctionner! Comme vous l'avez mentionné, je dois me concentrer sur gvim pour mettre à jour le contenu. Avez-vous une astuce pour le mettre à jour même sans vous concentrer? Merci encore pour votre aide.
Patrick

3
Je ne connais pas de solution à cela, malheureusement. Je serais stupéfait si vim pouvait le faire sans le changement de focus - il faudrait que vim interroge le système de fichiers pour voir quand il change. Je pense que vous auriez besoin d'un plugin pour cela.
Peter

2
@Peter J'ai fait un tel plugin il y a quelque temps. Voir également cette question et ma réponse . pour plus de détails sur son autoreadfonctionnement et ses limites.
Martin Tournoij

63

Je ne sais pas automatiquement, mais vous pouvez taper:

:e!

pour recharger le fichier


Bien que cette approche ne mette pas à jour automatiquement le contenu, elle affiche le contenu mis à jour. Merci pour votre réponse!
Patrick

31

Mettez ce qui suit dans votre .vimrc:

"vérifier une fois après 4 s d'inactivité en mode normal
définir la lecture automatique                                                                                                                                                                                    
au CursorHold * checktime                                                                                                                                                                       

Génial! Fonctionne bien, même avec un avertissement si vous avez modifié ce fichier depuis le dernier rechargement.
zoujyjs

1
La première réponse n'a pas fonctionné pour moi, mais cela fonctionne! :-)
Ionică Bizău

4
Le "toutes les 4 secondes" n'est pas vrai. Cela ne vérifiera qu'une seule fois après 4 s d'inactivité en mode normal. Donc, si vous ne faites rien dans un autre tampon pendant une longue période, il ne sera pas mis à jour, mais ce serait le cas si vous déplacez simplement le curseur et attendez 4s. Une autre option consiste à appeler manuellement ": checktime" pour mettre à jour (après avoir défini la lecture automatique). Malheureusement, il ne semble pas y avoir de support de sondage dans vim, il n'y a donc pas de vraie réponse à la question des OP.
David Ljung Madison Stellar

1
Je viens de tomber sur ça. Si vous modifiez checktime pour appeler une fonction personnalisée et ajoutez "call feedkeys (" lh ")" à la fin de la fonction, elle se déclenchera toutes les 4 secondes.
flukus

@DavidLjungMadison vous avez raison, je vais éditer le message pour éviter cette erreur
Phan Hai Quang

9

comme @flukus l'a dit dans un commentaire à une réponse précédente, vous pouvez call feedkeys["lh"](cela déplace le curseur vers la droite et le retour vers la gauche, ce qui normalement ne fait pas de mal lors de la visualisation d'un fichier journal)

Donc, si vous combinez le reste de la réponse, vous avez un oneliner que vous pouvez exécuter depuis ex (whithin vim) si nécessaire:

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


(si vous voulez sauter (presque) à la fin du fichier, utilisez simplement "G" au lieu de "lh" avec les touches d'alimentation)

Explication:
- lecture automatique : lit le fichier lorsqu'il est modifié de l'extérieur (mais il ne fonctionne pas tout seul, il n'y a pas de minuterie interne ou quelque chose du genre. Il ne lira le fichier que lorsque vim effectue une action, comme une commande dans ex :!
- CursorHold * checktime : lorsque le curseur n'est pas déplacé par l'utilisateur pendant le temps spécifié dans 'updatetime' (qui est de 4000 millisecondes par défaut), checktime est exécuté, qui vérifie les changements de l'extérieur du fichier
- appelez feedkeys ("lh") : le curseur est déplacé une fois, à droite et en arrière à gauche. et puis rien ne se passe (... ce qui signifie que CursorHold est déclenché, ce qui signifie que nous avons une boucle )

De plus, vous pouvez :set syntax=logtalkcolorer le journal

Pour arrêter le défilement lors de l'utilisation call feedkeys("G"), exécutez :set noautoread- maintenant vim dira que le fichier a été modifié et demandera si l'on veut lire les modifications ou non)

(Cela a-t-il des effets secondaires?)

Edit: je vois un effet secondaire: si on utilise "G" comme feedkey, il fera défiler vers le bas chaque tampon actuellement ouvert?! Il n'est donc pas possible de travailler dans le tampon gauche d'une fenêtre de splittet tout en faisant défiler automatiquement le tampon droit dans un fichier journal


4

Collez ceci dans votre .vimrc et cela devrait fonctionner comme un boss. (Pris à partir 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)

1
C'est la réponse préférée pour remédier aux lacunes de la lecture automatique du terminal.
mcanfield le

3
@mcanfield Non, ce n'est pas le cas car cela ne "surveille toujours pas les changements". Vous devez toujours avoir Vim actif et il interroge toujours (ne regarde pas) sur un ensemble limité d'événements. CursorHoldest exécuté une fois . Donc, si vous allez prendre un café, ou faites quelque chose dans une autre fenêtre, il ne sera pas mis à jour.
Martin Tournoij

4
Ce script est également fourni sous forme de plugin Vim: vim-autoread .
stephen.hanson

1
@ stephen.hanson Merci pour le lien, ce plugin fonctionne bien pour moi!
Tropilio


2

Si unix + neovim

:term tail -f <filename>

Évidemment, cela ne fonctionnera pas pour tout le monde, mais c'est comme ça que je le fais.



0

VIM vous avertira lorsqu'un fichier a été mis à jour afin que vous n'écrasiez pas les modifications apportées depuis que vous l'avez ouvert. Il vous demandera à ce stade de recharger le fichier.


1
Merci pour votre réponse, mais vim ne m'a pas prévenu lorsque le fichier a été modifié dans mon système :(
Patrick
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.