Come prevenire il rallentamento quando un processo inferiore genera linee lunghe?


14

Uso Emacs con Geiser per hackerare un po 'di codice Scheme. Mentre sto giocando nel REPL, a volte valuto le espressioni che portano a un sacco di output, spesso tutto su una riga.

Ad esempio, ho appena giocato con SRFI-41 (stream) e ho creato un flusso di caratteri da un file di grandi dimensioni; poi ho forzato il flusso e Geiser ha inserito nel mio buffer l'intero contenuto del file come flusso di caratteri. Quasi immediatamente, Emacs si è fermato quando sempre più personaggi sono stati aggiunti alla linea di output, e non importa per quanto tempo ho continuato a premere C-go C-c C-cnon sono riuscito a fermare Emacs (o Geiser).

Ciò ha interrotto la mia intera sessione di Emacs poiché Emacs ora ignora completamente il mio input, pensando che debba dare la priorità alla stampa di questo enorme flusso di caratteri su una riga in un buffer REPL di Geiser che non risponde.

C'è qualcosa che posso fare per proteggere la mia sessione di Emacs dalla mia distruttiva curiosità? (Perché Emacs diventa così lento quando si visualizzano comunque linee molto lunghe?) Posso impostare un limite per le linee lunghe e dire a Emacs che va bene semplicemente non provare a visualizzare linee molto lunghe?



2
Bene, la mia domanda non riguarda la visualizzazione di linee lunghe di per sé; Voglio sapere come posso evitare questo genere di cose in primo luogo (Emacs legge la riga da un processo inferiore, non è letto da un file che potrei correggere); ed è su come posso evitare di perdere la mia sessione di Emacs per la dedizione di Emacs a un singolo buffer dinamico.
rekado,

"Beh, la mia domanda non riguarda la visualizzazione di righe lunghe" Quindi forse dovresti cambiare il titolo. Forse vuoi filtrare l'output del processo inferiore e aggiungere una nuova riga dopo un certo numero di caratteri?
tata

Davvero, questo ha poco a che fare con le lunghe file. yesin un ansi-termesempio ha un effetto simile (ma non così orribile). In realtà è solo il volume di testo a dare una pausa a emacs.
PythonNut

L'inserimento di testo in un buffer è piuttosto veloce, sono le operazioni di visualizzazione che lo fanno apparire più lento di quanto non sia in realtà. Ad essere sincero, l'esecuzione yesin un emulatore di terminale VTE massimizza tutti i miei core della CPU, quindi non lo userei come esempio.
Wasamasa,

Risposte:


12

Come già risposto nei commenti, Emacs sta diventando molto lento nel suo nuovo display per le linee lunghe è un problema ben noto . Risolvere il problema sarebbe molto bello, ma ha bisogno di molti pensieri per essere rimosso correttamente. Ho un'idea di come potrebbe essere realizzato sulla base della sezione 6.3 di questo documento (in sostanza, memorizza le informazioni sulla linea visiva nel buffer corrente e aggiornalo sull'inserimento di spazi bianchi, proprietà di visualizzazione, modifiche alle finestre, ecc., Quindi usa quelle informazioni in il codice di visualizzazione per evitare la scansione per tutto il tempo), ma non ho abbastanza familiarità con gli interni C per eseguirlo.

Ci sono soluzioni alternative però. I più ovvi sarebbero l'ottimizzazione dei parametri relativi al display (come, abilitare il troncamento della linea visiva nell'istanza grafica di Emacs, usare un Emacs non grafico per farlo automaticamente, disabilitare le funzionalità Bidi, ecc.) E preelaborare il contenuto del file che si ' rilettura. Uno meno ovvio è la post-elaborazione automatica dei file, che si tratti effettivamente di troncare le loro linee o di aggiungere proprietà di testo che fanno apparire le linee più corte di quanto non siano in realtà. Per trasformare questa in una risposta più interessante, presenterò un brutto hack della precedente opzione che funzionerà solo per le comintmodalità derivate:

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

Questo definisce my-comint-shorten-long-linesuna funzione che prende una stringa che può essere composta da molte righe e usa il potere delle espressioni regolari per sostituire qualsiasi riga in essa con una lunghezza di 80 caratteri o più con una versione abbreviata che visualizza il testo originale quando ci si passa sopra. Se utilizzato come hook comint-preoutput-filter-functions, filtrerà tutto l' comintoutput prima che venga visualizzato.

Tuttavia, questa interpretazione dell'hacker ha una debolezza piuttosto grave. Nelle modalità in cui è in corso la fontificazione di base (come, M-x ielm), taglierà felicemente le linee che fanno parte di una stringa e in questo modo fontifica tutto fino alla prossima citazione come stringa! Non è quello che vogliamo e può essere risolto con un po 'più di padronanza della regex (ma presumibilmente si romperà all'interno di un REPL per un linguaggio come Python). Mentre ci siamo, evidenziamo anche l'output abbreviato:

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

È un po 'meglio, ma è ancora brutto. Passare il mouse sull'output di qualcosa come find /in M-x shellnon è attraente (vorremmo idealmente solo visualizzare la linea non accorciata, non tutto l'output), il rilevamento delle stringhe è al massimo rudimentale e il troncamento potrebbe essere indicato meglio con le ellissi invece di fonti di tutto. Inoltre, non è nemmeno garantito che il testo in arrivo non venga trasformato in lotti. Tutto ciò urla per aver eseguito la fase di elaborazione in un buffer temporaneo, ma sarà lasciato al lettore come esercizio (o all'autore come potenziale post sul blog).


4

Allo stesso modo di Python, la soluzione su python-mode.el, https://launchpad.net/python-mode , è quella di connettersi al processo direttamente, non tramite la modalità comint.

Si basa su start-processe process-send-string

Ad esempio vedere funzioni py--start-fast-processepy--fast-send-string-intern

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.