Jak zapobiegać spowolnieniu, gdy gorsze procesy generują długie linie?

14

Używam Emacsa z Geiserem do hakowania kodu Scheme. Podczas zabawy w REPL czasami oceniam wyrażenia, które dają wiele wyników, często wszystkie w jednym wierszu.

Na przykład, właśnie grałem z SRFI-41 (strumienie) i stworzyłem strumień znaków z dużego pliku; następnie wymusiłem strumień i Geiser zapisał całą zawartość pliku jako strumień znaków do mojego bufora. Niemal natychmiast Emacs zatrzymał się, gdy coraz więcej znaków było dołączanych do linii wyjściowej i bez względu na to, jak długo naciskałem C-glub C-c C-cnie mogłem zatrzymać Emacsa (lub Geisera).

To zepsuło całą moją sesję Emacsa, ponieważ Emacs teraz całkowicie ignoruje mój wkład, myśląc, że musi dać pierwszeństwo wydrukowaniu tego ogromnego strumienia znaków w jednym wierszu w niereagującym buforze Geiser REPL.

Czy jest coś, co mogę zrobić, aby ochronić moją sesję Emacsa przed niszczycielską ciekawością? (Dlaczego Emacs i tak wyświetla się tak wolno podczas wyświetlania bardzo długich linii?) Czy mogę ustawić limit długich linii i powiedzieć Emacsowi, że nic nie próbuję wyświetlać bardzo długich linii?

rekado
źródło
2
Cóż, moje pytanie nie dotyczy wyświetlania długich linii per se; Chcę przede wszystkim wiedzieć, jak mogę tego uniknąć (Emacs czyta wiersz z gorszego procesu, nie jest odczytywany z pliku, który mógłbym naprawić); i chodzi o to, jak mogę zapobiec utracie sesji Emacsa z powodu poświęcenia się Emacsa pojedynczemu buforowi dynamicznemu.
rekado
„Cóż, moje pytanie nie dotyczy wyświetlania długich linii”. Może więc powinieneś zmienić tytuł. Być może chcesz odfiltrować gorszy wynik procesu i dodać nową linię po określonej ilości znaków?
niania
Naprawdę jednak nie ma to nic wspólnego z długimi kolejkami. yesw sposób ansi-termna przykład jest podobny (nie że okropnym) mocy. Naprawdę to tylko objętość tekstu powoduje pauzę w emacsie.
PythonNut,
Wstawianie tekstu w buforze jest dość szybkie, to operacje ponownego wyświetlania sprawiają, że wydaje się on wolniejszy niż w rzeczywistości. Szczerze mówiąc, uruchomienie yesw emulatorze terminala VTE maksymalnie wykorzystuje wszystkie moje rdzenie procesora, więc nie użyłbym tego jako przykładu.
wasamasa,

Odpowiedzi:

12

Jak już wspomniano w komentarzach, Emacs bardzo powoli spowalniający wyświetlanie długich linii jest dobrze znanym problemem . Naprawienie go byłoby bardzo miłe, ale wymaga wiele przemyślenia, aby poprawnie go wyciągnąć. Mam pomysł, jak można to osiągnąć na podstawie sekcji 6.3 tego dokumentu (w zasadzie przechowuj informacje o liniach wizualnych w bieżącym buforze i aktualizuj je po wstawieniu białych znaków, właściwości wyświetlania, zmian okna itp., A następnie użyj tych informacji w ponownie wyświetlaj kod, aby uniknąć ciągłego skanowania), ale nie znam wystarczająco wewnętrznych elementów C, aby go pobrać.

Istnieją jednak obejścia. Najbardziej oczywiste z nich to dostrajanie parametrów związanych z wyświetlaniem (np. Włączanie wizualnego obcięcia linii w graficznej instancji Emacsa, używanie nie graficznego Emacsa, aby to zrobić automatycznie, wyłączanie funkcji Bidi itp.) I wstępne przetwarzanie zawartości pliku, który „ ponowne wczytywanie. Mniej oczywistym jest automatyczne przetwarzanie plików, czy to przez obcięcie ich linii lub dodanie właściwości tekstowych, które sprawiają, że linie wydają się krótsze niż w rzeczywistości. Aby zamienić to w ciekawszą odpowiedź, przedstawię dość brzydki hack poprzedniej opcji, która będzie działać tylko dla cominttrybów generowanych:

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

Definiuje my-comint-shorten-long-linesto funkcję, która pobiera ciąg znaków prawdopodobnie składający się z wielu wierszy i wykorzystuje moc wyrażeń regularnych do zastąpienia dowolnego wiersza o długości 80 znaków lub większej skróconą wersją, która wyświetla oryginalny tekst po najechaniu na niego kursorem. Jeśli zostanie użyty jako zaczep comint-preoutput-filter-functions, filtruje wszystkie comintdane wyjściowe przed ich wyświetleniem.

Jednak wykonanie hacka ma dość poważną słabość. W trybach, w których działa podstawowa czcionka (jak, M-x ielm), z radością odetnie linie, które są częścią łańcucha i w ten sposób będzie fontantyzować wszystko, aż do następnego cytatu jako łańcucha! To nie jest to, czego chcemy i może być naprawione za pomocą nieco większej znajomości wyrażeń regularnych (ale prawdopodobnie złamie się w REPL dla języka takiego jak Python). Skoro już o tym mowa, podkreślmy także skróconą wydajność:

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

To trochę lepiej, ale nadal brzydko. Umieszczanie wskaźnika na wyjściu czegoś takiego jak find /w M-x shellnie jest atrakcyjne (najlepiej chcielibyśmy wyświetlać niesortowaną linię, a nie wszystkie dane wyjściowe), wykrywanie ciągów jest w najlepszym razie szczątkowe, a obcięcie można lepiej wskazać elipsami zamiast wszystko. Co więcej, nie ma nawet gwarancji, że nadchodzący tekst nie zostanie przekształcony w partie. Wszystko to krzyczy za wykonanie kroku przetwarzania w tymczasowym buforze, ale zostanie pozostawione czytelnikowi jako ćwiczenie (lub autorowi jako potencjalny post na blogu).

wasamasa
źródło
4

Ponieważ tak samo stało się z Pythonem, rozwiązaniem w python-mode.el, https://launchpad.net/python-mode jest połączenie z procesem bezpośrednio, a nie poprzez tryb komend.

Opiera się na start-processłańcuchu przetwarzania i wysyłania

Na przykład zobacz funkcje py--start-fast-processipy--fast-send-string-intern

Andreas Röhler
źródło