Comment puis-je faire en sorte que Vim lise automatiquement un fichier alors qu'il n'a pas le focus?

29

J'utilise VIm pour toutes sortes de choses (ou gVim dans ce cas), y compris la surveillance de la sortie écrite dans un fichier; J'utilise autoreadpour que Vim relise le fichier, ce qu'il fait chaque fois que je lui passe le focus du clavier.

Existe-t-il un moyen de faire mettre à jour Vim le tampon même si je ne change pas le focus du clavier? J'ai essayé le réglage, checktimemais il ne semble pas avoir d'effet alors que le focus du clavier est ailleurs.

La sortie que je surveille remplace complètement le fichier de sortie; et je n'y regarde pas tail -f. Il existe d'autres options, comme le piping dans une nouvelle instance à chaque fois, ou le piping dans lessou quelque chose, mais ce serait cool si cela pouvait être fait avec VIm.

falstro
la source
@Carpetsmoker que diriez- CursorHoldvous de l' événement? Si Vim n'a pas de focus, il devrait se déclencher toutes les n secondes.
muru
1
@muru Non, CursorHoldn'est exécuté qu'une seule fois, cela est explicitement documenté comme suit
Martin Tournoij
1
J'ai enlevé le gvim tag à nouveau, j'espère que ce bien ;-) Comme je le vois, cette question est pas vraiment à propos gVim, le changement de mise au point est juste un événement sur lequel Vim vérifie si le fichier est modifié (il y a tout un tas, voir ma réponse pour plus de détails). La plupart, sinon la totalité, des moyens d'améliorer cela fonctionneront bien dans Vim et gVim.
Martin Tournoij
@Carpetsmoker ah, j'avais l'impression que gVim vérifiait régulièrement alors qu'il avait le focus clavier (ce qui en faisait une question gVim), mais il semble que je me suis trompé. Merci d'avoir clarifié cela.
falstro

Réponses:

20

Mise à jour 2015-06-25 :

  • J'ai abandonné la méthode "shell", car elle était trop dysfonctionnelle. Il a arrêté le mode d'insertion et laissé les processus zombies. Regardez l'historique des révisions de ce message si vous voulez vraiment le voir de toute façon.
  • J'ai créé un plugin à partir de cela: auto_autoread.vim . Pour le moment, c'est effectivement le même que le code ci-dessous, mais je vous recommande d'utiliser le plugin car il est susceptible de recevoir des mises à jour.

Que fait autoread-il?

Pour répondre à cette question, nous devons d'abord comprendre ce que fait l' autoreadoption et, plus important encore, ce qu'elle ne fait pas .

Malheureusement, il :help 'autoread' n'a pas beaucoup d'informations à ce sujet, il dit simplement "qu'un fichier a été détecté comme ayant été modifié en dehors de Vim" . Comment Vim détecte-t-il qu'un fichier est modifié? Sur certaines actions, Vim vérifie l'heure de modification du fichier.

Quand:

  • :checktime est utilisé;
  • un tampon est entré;
  • :diffupdate est utilisé;
  • :e est émis pour un fichier qui a déjà un tampon;
  • exécuter une commande externe avec !;
  • retour au premier plan ( ^Z, fg, seulement si la coquille a le contrôle de l' emploi);

pour gVim, cela se fait également lorsque:

  • fermer le menu "clic droit" (soit en sélectionnant quelque chose, soit simplement en le fermant);
  • le focus est changé (c'est ce que vous avez déjà remarqué);
  • en fermant la boîte de dialogue des navigateurs de fichiers qui apparaît si vous utilisez "fichier -> ouvrir", "fichier -> enregistrer sous" dans le menu (ainsi que d'autres endroits).

J'ai rassemblé ces informations de la source vim de localiser tous les appels vers les buf_check_timestamp(), check_timestamps()fonctions, et les lieux où need_check_timestampsest mis à TRUE.

J'ai peut-être manqué certains événements, mais l'essentiel à retenir est que Vim vérifie uniquement si le fichier est modifié dans un ensemble très limité de circonstances . Il n'effectue certainement pas "d'interrogation" sur le fichier pour les changements de n secondes, ce qui est essentiellement ce que vous recherchez.

Donc, pour vous, ce set autoreadn'est pas suffisant.

Utiliser Python

Cela planifie un thread Python pour s'exécuter en arrière-plan, il s'exécutera :checktimetoutes les n secondes. Si autoreadest activé , cela rechargera le tampon du disque, sinon il avertira simplement.

Cela nécessite que Vim ait +pythonou +python3en :version. Il devrait fonctionner sur toutes les plateformes (y compris 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

Vous pouvez commencer cela en utilisant :call AutoreadPython(); vous pouvez bien sûr le faire dans un autocmd; par exemple:

autocmd *.c call AutoreadPython()

Épilogue

Il existe en fait plus de méthodes, par exemple, vous pouvez utiliser un outil tel que entrou le Python inotifyou le gaminmodule pour surveiller les modifications d'un fichier, :checktimevérifie également tous les tampons si aucun argument n'est fourni, cela pourrait être amélioré en vérifiant uniquement un seul tampon ou un certain fichier.
Cependant, cette réponse est déjà assez longue :-) Ces méthodes devraient (espérons-le!) Fonctionner correctement pour la plupart des scénarios, ou devraient être facilement adaptables à votre scénario.

PS. J'ai également essayé d'utiliser Ruby, mais malheureusement, les threads Ruby (en utilisant Thread) ne s'exécutent pas en arrière-plan comme le fait Python, donc je n'ai pas pu faire fonctionner cela (peut-être qu'il y a un autre moyen, cependant?)

Martin Tournoij
la source
2

J'ai fait un petit plugin vim-autoread qui utilise tail -fpour mettre à jour le tampon en arrière-plan de manière asynchrone. Cela nécessite évidemment la fonction de travail de Vim Version 8.

Utilisez :AutoReadpour l'allumer et l' :AutoRead!éteindre.

Christian Brabandt
la source
Une version compatible NeoVim serait géniale!
Andrew
@AndrewMacFie Je ne vois pas pourquoi cela ne fonctionnerait pas sur Neovim.
Christian Brabandt
le manque de support des jobs Vim 8 dans NeoVim je pensais?
Andrew
@AndrewMacFie oh c'est probablement vrai. Comme je n'utilise pas neovim, je ne peux pas le rendre compatible NeoVim. Cependant, un RP serait le bienvenu :)
Christian Brabandt
assez juste:)
Andrew
1

Dans Neovim, vous pouvez utiliser la commande suivante qui ouvrira un tampon de terminal exécutant la commande tail.

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

Cela continuera de fonctionner même si le fichier est supprimé et recréé.

Ou ajoutez ce qui suit à votre $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
la source
1

de cette réponse (se référant à une réponse de PhanHaiQuang et un commentaire de flukus )

On peut exécuter ce oneliner depuis ex (dans vim) en cas de besoin (ou mettre chaque commande dans vimrc, lorsque les fichiers journaux sont ouverts.)

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

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

eli
la source