Comment éviter un ralentissement lorsqu'un processus inférieur génère de longues files d'attente?


14

J'utilise Emacs avec Geiser pour pirater du code Scheme. Comme je joue dans le REPL, j'évalue parfois des expressions qui entraînent beaucoup de sorties, souvent toutes sur une seule ligne.

Par exemple, je viens de jouer avec SRFI-41 (flux) et j'ai créé un flux de personnage à partir d'un gros fichier; puis j'ai forcé le flux et Geiser a bloqué tout le contenu du fichier sous forme de flux de caractères dans mon tampon. Presque immédiatement, Emacs s'est arrêté au fur et à mesure que de plus en plus de personnages étaient ajoutés à la ligne de sortie, et peu importe combien de temps je continuais d'appuyer C-gou C-c C-cje ne pouvais pas arrêter Emacs (ou Geiser).

Cela a interrompu toute ma session Emacs car Emacs ignore maintenant complètement mon entrée, pensant qu'il doit donner la priorité à l'impression de ce flux de caractères massif sur une seule ligne dans un tampon Geiser REPL qui ne répond pas.

Puis-je faire quelque chose pour protéger ma session Emacs de ma curiosité destructrice? (Pourquoi Emacs devient-il si lent lors de l'affichage de très longues lignes?) Puis-je définir une limite pour les longues lignes et dire à Emacs qu'il est tout simplement acceptable de ne pas afficher les très longues lignes?



2
Eh bien, ma question ne concerne pas l'affichage des longues lignes en soi; Je veux savoir comment je peux éviter ce genre de chose en premier lieu (Emacs lit la ligne d'un processus inférieur, ce n'est pas lu à partir d'un fichier que je pourrais corriger); et c'est sur la façon dont je peux éviter de perdre ma session Emacs à cause du dévouement d'Emacs à un seul tampon dynamique.
rekado

"Eh bien, ma question n'est pas d'afficher de longues lignes" Alors peut-être devriez-vous changer votre titre. Vous souhaitez peut-être filtrer la sortie de processus inférieure et ajouter une nouvelle ligne après un certain nombre de caractères?
nounou

En réalité, cela n'a pas grand-chose à voir avec les longues lignes. yesdans un ansi-termpar exemple a un effet similaire (mais pas si horrible). Vraiment, c'est juste le volume de texte qui donne une pause à emacs.
PythonNut

L'insertion de texte dans un tampon est assez rapide, ce sont les opérations de réaffichage qui le font apparaître plus lentement qu'il ne l'est en réalité. Pour être honnête, l'exécution yesdans un émulateur de terminal VTE maximise tous mes cœurs de processeur, donc je ne l'utiliserais pas comme exemple.
wasamasa

Réponses:


12

Comme déjà répondu dans les commentaires, Emacs devenant très lent dans son réaffichage pour les longues lignes est un problème bien connu . Le réparer serait très bien, mais a besoin de beaucoup de réflexion pour être retiré correctement. J'ai une idée de la façon dont cela pourrait être accompli sur la base de la section 6.3 de ce document (en gros, stockez les informations de ligne visuelle dans le tampon actuel et mettez-le à jour lors de l'insertion d'espaces, des propriétés d'affichage, des changements de fenêtre, etc., puis utilisez ces informations dans le code de réaffichage pour éviter de le rechercher tout le temps), mais je ne connais pas assez bien les internes C pour le retirer.

Il existe cependant des solutions de contournement. Les plus évidents seraient le réglage des paramètres liés à l'affichage (comme l'activation de la troncature de ligne visuelle dans l'instance Emacs graphique, l'utilisation d'un Emacs non graphique pour que cela se fasse automatiquement, la désactivation des fonctionnalités Bidi, etc.) et le prétraitement du contenu du fichier que vous '' relire. Un autre moins évident est le post-traitement automatique des fichiers, que ce soit en tronquant réellement leurs lignes ou en ajoutant des propriétés de texte qui rendent les lignes plus courtes qu'elles ne le sont réellement. Pour transformer cela en une réponse plus intéressante, je vais présenter un hack assez laid de l'ancienne option qui ne fonctionnera que pour les comintmodes dérivés:

(defun my-comint-shorten-long-lines (text)
  (let* ((regexp "^\\(.\\{80\\}\\).*?$")
         (shortened-text (replace-regexp-in-string regexp "\\1" text)))
    (if (string= shortened-text text)
        text
      (propertize shortened-text 'help-echo text))))

(add-hook 'comint-preoutput-filter-functions 'my-comint-shorten-long-lines)

Cela définit my-comint-shorten-long-lines, une fonction qui prend une chaîne pouvant être composée de plusieurs lignes et utilise la puissance des expressions régulières pour remplacer toute ligne en elle avec une longueur de 80 caractères ou plus par une version raccourcie qui affiche le texte original lorsque vous passez la souris dessus. Lorsqu'il est utilisé comme hook, comint-preoutput-filter-functionsil filtrera toutes les comintsorties avant de les afficher.

Cependant, cette interprétation du hack a une faiblesse assez sérieuse. Dans les modes qui ont une police de base en cours (comme, M-x ielm), il coupera volontiers les lignes qui font partie d'une chaîne et de cette façon, tout police jusqu'à la prochaine citation sous forme de chaîne! Ce n'est pas ce que nous voulons et peut être corrigé avec un peu plus de maîtrise des regex (mais cela se brisera probablement dans un REPL pour un langage comme Python). Pendant que nous y sommes, soulignons également la sortie raccourcie:

(defun my-comint-shorten-long-lines (text)
  (let* ((regexp "^\\(.\\{80\\}\\).*?\\(\"?\\)$")
         (shortened-text (replace-regexp-in-string regexp "\\1\\2" text)))
    (if (string= shortened-text text)
        text
      (propertize shortened-text 'font-lock-face 'shadow 'help-echo text))))

(add-hook 'comint-preoutput-filter-functions 'my-comint-shorten-long-lines)

C'est un peu mieux, mais toujours moche. Planer sur la sortie de quelque chose comme find /dans M-x shelln'est pas attrayant (nous voudrions idéalement seulement afficher la ligne non raccourcie, pas toutes les sorties), la détection des chaînes est au mieux rudimentaire et la troncature pourrait être mieux indiquée avec des ellipses au lieu de tout faire. De plus, il n'est même pas garanti que le texte entrant ne soit pas transformé en lots. Tout cela hurle de faire l'étape de traitement dans un tampon temporaire, mais sera laissé au lecteur comme exercice (ou à l'auteur comme article de blog potentiel).


4

Comme cela s'est produit avec Python également, la solution sur python-mode.el, https://launchpad.net/python-mode , consiste à se connecter directement au processus, pas via le mode comint.

S'appuie sur start-processet chaîne d'envoi de processus

Par exemple, voir fonctions py--start-fast-processetpy--fast-send-string-intern

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.