¿Cómo prevenir la desaceleración cuando un proceso inferior genera largas colas?

14

Uso Emacs con Geiser para hackear algún código de Scheme. Mientras juego en el REPL, a veces evalúo expresiones que resultan en una gran cantidad de resultados, a menudo todos en una línea.

Por ejemplo, acabo de jugar con SRFI-41 (secuencias) y creé una secuencia de caracteres a partir de un archivo grande; luego forcé la secuencia y Geiser vomitó todo el contenido del archivo como una secuencia de caracteres en mi búfer. Casi de inmediato, Emacs se detuvo cuando más y más caracteres se adjuntaron a la línea de salida, y no importa cuánto tiempo seguí presionando C-go C-c C-cno pude hacer que Emacs (o Geiser) se detuviera.

Esto rompió toda mi sesión de Emacs ya que Emacs ahora ignora por completo mi entrada, pensando que debe dar prioridad a imprimir esta secuencia de caracteres masiva todo en una línea en un búfer Geiser REPL que no responde.

¿Hay algo que pueda hacer para proteger mi sesión de Emacs de mi curiosidad destructiva? (¿Por qué Emacs se vuelve tan lento cuando se muestran líneas muy largas?) ¿Puedo establecer un límite para las líneas largas y decirle a Emacs que está bien simplemente no intentar mostrar líneas muy largas?

rekado
fuente
2
Bueno, mi pregunta no se trata de mostrar largas líneas per se; Quiero saber cómo puedo evitar este tipo de cosas en primer lugar (Emacs lee la línea de un proceso inferir, no se lee de un archivo que podría arreglar); y se trata de cómo puedo evitar perder mi sesión de Emacs por la dedicación de Emacs a un único búfer dinámico.
rekado
"Bueno, mi pregunta no es sobre mostrar líneas largas" Entonces quizás deberías cambiar tu título. ¿Quizás desee filtrar la salida del proceso inferior y agregar una nueva línea después de una cierta cantidad de caracteres?
niñera
Realmente, sin embargo, esto tiene poco que ver con largas colas. yesen una ansi-term, por ejemplo, tiene una similar (pero no que horrible) efecto. Realmente es solo el volumen de texto lo que da pausa a emacs.
PythonNut
La inserción de texto en un búfer es bastante rápida, son las operaciones de visualización que hacen que parezca más lento de lo que realmente es. Para ser honesto, ejecutar yesen un emulador de terminal VTE maximiza todos mis núcleos de CPU, por lo que no lo usaría como ejemplo.
wasamasa

Respuestas:

12

Como ya se respondió en los comentarios, Emacs se está volviendo muy lento en su nueva visualización para largas colas es un problema bien conocido . Arreglarlo sería muy bueno, pero necesita mucho pensamiento para que se realice correctamente. Tengo una idea de cómo podría lograrse según la sección 6.3 de este documento (básicamente, almacene información de línea visual en el búfer actual y actualícela al insertar espacios en blanco, mostrar propiedades, cambios de ventana, etc., luego use esa información en el código de re-visualización para evitar buscarlo todo el tiempo), pero no estoy lo suficientemente familiarizado con las partes internas de C para lograrlo.

Sin embargo, hay soluciones alternativas. Los más obvios serían ajustar los parámetros relacionados con la pantalla (como habilitar el truncamiento de la línea visual en la instancia gráfica de Emacs, usar un Emacs no gráfico para hacerlo automáticamente, deshabilitar las funciones de Bidi, etc.) y preprocesar el contenido del archivo ' está leyendo. Una menos obvia es el procesamiento posterior automático de los archivos, ya sea truncando sus líneas o agregando propiedades de texto que hacen que las líneas parezcan más cortas de lo que realmente son. Para convertir esto en una respuesta más interesante, presentaré un truco bastante feo de la opción anterior que solo funcionará para los comintmodos derivados:

(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)

Esto define my-comint-shorten-long-lines, una función que toma una cadena que posiblemente consta de muchas líneas y utiliza el poder de las expresiones regulares para reemplazar cualquier línea con una longitud de 80 caracteres o más con una versión abreviada que muestra el texto original al pasar el mouse sobre ella. Cuando se usa como enlace comint-preoutput-filter-functions, filtrará toda la comintsalida antes de que se muestre.

Sin embargo, esta versión del hack tiene una debilidad bastante grave. En los modos que tienen una fontificación básica (como, M-x ielm), ¡cortará felizmente las líneas que forman parte de una cadena y de ese modo se formará todo hasta la próxima cita como cadena! Eso no es lo que queremos y se puede solucionar con un poco más de dominio de expresiones regulares (pero presumiblemente se romperá dentro de un REPL para un lenguaje como Python). Mientras estamos en eso, destaquemos también la salida acortada:

(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)

Eso está un poco mejor, pero sigue siendo feo. Pasar el cursor sobre la salida de algo como find /en M-x shellno es atractivo (idealmente solo queremos mostrar la línea no acortada, no toda la salida), la detección de cadenas es rudimentaria en el mejor de los casos y el truncamiento podría indicarse mejor con puntos suspensivos en lugar de escribir todo. Además de eso, ni siquiera se garantiza que el texto entrante no se convierta en lotes. Todo esto grita por hacer el paso de procesamiento en un búfer temporal, pero se dejará al lector como ejercicio (o al autor como posible publicación de blog).

wasamasa
fuente
4

Como esto sucedió también con Python, la solución en python-mode.el, https://launchpad.net/python-mode , es conectarse al proceso directamente, no a través del modo de impresión.

Se basa en start-processy procesar-enviar-cadena

Por ejemplo ver funciones py--start-fast-processypy--fast-send-string-intern

Andreas Röhler
fuente