Як запобігти уповільненню, коли неповноцінні процеси генерують довгі лінії?


14

Я використовую Emacs з Geiser, щоб зламати якийсь код схеми. Коли я граю в REPL, я іноді оцінюю вирази, які призводять до великої кількості результатів, часто все в одному рядку.

Наприклад, я щойно грав з SRFI-41 (потоки) і створив символьний потік з великого файлу; тоді я витіснив потік, і Гейзер заніс весь вміст файлу як поток символів у мій буфер. Майже одразу Emacs зупиняється, оскільки все більше символів додаються до вихідного рядка, і незалежно від того, як довго я натискав C-gабо C-c C-cне міг зупинити Emacs (або Geiser).

Це порушило весь мій сеанс Emacs, оскільки Emacs тепер повністю ігнорує моє введення, думаючи, що йому потрібно надавати пріоритет друкуванню цього масивного потоку символів на одній лінії в невідповідний буфер відклику Geiser REPL.

Чи можу я щось зробити, щоб захистити сеанс Emacs від моєї руйнівної цікавості? (Чому Emacs все одно стає настільки повільним, коли відображає дуже довгі рядки?) Чи можу я встановити обмеження для довгих ліній і сказати Emacs, що нормально просто не намагатися відображати дуже довгі рядки?



2
Ну, моє питання не в тому, щоб відображати довгі рядки самі по собі; Мені хочеться знати, як я можу уникнути подібних речей в першу чергу (Emacs читає рядок із певного процесу, він не читається з файлу, який я міг би виправити); і про те, як я можу запобігти втраті моєї сесії Emacs на відданість Emacs одному динамічному буфері.
rekado

"Ну, моє питання не про показ довгих рядків" Тоді, можливо, вам слід змінити назву. Можливо, ви хочете відфільтрувати нижчий результат процесу та додати новий рядок після певної кількості символів?
няня

Дійсно, хоча це мало стосується довгих ліній. yesв ansi-term, наприклад , має аналогічний (але не , що жахливий) ефекту. Дійсно, це просто об'єм тексту, який дає паузу Emacs.
PythonNut

Вставлення тексту в буфер відбувається досить швидко, саме операції повторного відображення роблять це повільніше, ніж є насправді. Якщо чесно, запуск yesв емуляторі терміналу VTE максимізує всі мої CPU ядра, тому я не використовую це як приклад.
wasamasa

Відповіді:


12

Як уже було сказано в коментарях, Emacs стає дуже повільним у своїй повторній програмі для довгих ліній - добре відоме питання . Виправити це було б дуже приємно, але потрібно багато думок, щоб правильно їх зняти. У мене є уявлення про те, як це могло бути здійснено на основі розділу 6.3 цього документа (в основному, зберігати візуальну інформацію про рядки у поточному буфері та оновлювати її при вставці пробілу, властивостях відображення, зміні вікон тощо), а потім використовувати цю інформацію в код повторного відображення, щоб уникнути сканування на ньому весь час), але я недостатньо знайомий із внутрішніми документами C, щоб його зняти.

Однак є й обхідні шляхи. Найбільш очевидними з них можуть бути налаштування параметрів, що стосуються дисплея (наприклад, включення візуального обрізання ліній в екземплярі графічного Emacs, використання неграфічного Emacs для автоматичного виконання, відключення функцій Bidi тощо) та попередня обробка вмісту файлу, який ви ' Повторне читання. Менш очевидний - це автоматично після обробки файлів, будь то насправді обрізання їх рядків або додавання властивостей тексту, які роблять рядки коротшими, ніж вони є насправді. Щоб перетворити це на більш цікаву відповідь, я представляю досить некрасивий хак колишньої опції, яка працюватиме лише для comintрежимів, що отримуються раніше:

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

Це визначає my-comint-shorten-long-linesфункцію, яка займає рядок, можливо, складається з багатьох рядків і використовує силу регулярних виразів, щоб замінити будь-який рядок в ній довжиною 80 символів і більше на скорочену версію, яка відображає оригінальний текст при наведенні на нього курсором. Якщо його використовувати як гачок, comint-preoutput-filter-functionsвін буде фільтрувати весь comintвихід, перш ніж його відображати.

Однак це відтворення хака має досить серйозну слабкість. У режимах, у яких триває основна фентифікація (наприклад, M-x ielm), вона з радістю буде відрізати лінії, що є частиною рядка, і таким чином впорядкує все до наступної цитати як рядок! Це не те, що ми хочемо, і це може бути виправлено за допомогою трохи кращого майстерності регулярних виразів (але, мабуть, воно введеться в REPL для такої мови, як Python). Поки ми до цього звернемо увагу, також виділимо скорочений вихід:

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

Це трохи краще, але все ж потворно. Наведення на висновок чогось подібного find /до M-x shellне є привабливим (ми в ідеалі хотіли б лише відобразити нескорочену лінію, а не весь вихід), виявлення рядків у кращому випадку є рудиментарним, і усікання може бути вказане краще еліпсами, а не присвячувати все. Крім того, навіть не гарантується, що текст, що надходить, не перетвориться на партії. Все це кричить за те, щоб зробити крок обробки у тимчасовому буфері, але читач залишиться як вправа (або автор як потенційна публікація в блозі).


4

Як це сталося з Python також, рішення на python-mode.el, https://launchpad.net/python-mode , полягає в підключенні до процесу безпосередньо, а не через режим comint.

Покладається на start-processі обробляє-send-string

Наприклад, див. Функції py--start-fast-processтаpy--fast-send-string-intern

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.