Как предотвратить замедление, когда низшие процессы генерируют длинные строки?

14

Я использую Emacs с Geiser, чтобы взломать код Scheme. Играя в REPL, я иногда оцениваю выражения, которые приводят к значительному выводу, часто все в одну строку.

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

Это прервало весь мой сеанс Emacs, так как Emacs теперь полностью игнорирует мой ввод, думая, что ему нужно отдавать приоритет печати этого массивного потока символов в одну строку в неотвечающий буфер Geiser REPL.

Что я могу сделать, чтобы защитить сеанс Emacs от моего разрушительного любопытства? (Почему Emacs так медленно работает при отображении очень длинных строк?) Могу ли я установить ограничение для длинных строк и сказать Emacs, что можно просто не пытаться отображать очень длинные строки?

rekado
источник
2
Ну, мой вопрос не о отображении длинных строк как таковых; Я хочу знать, как я могу избежать такого рода вещей (Emacs читает строку из неполного процесса, она не читается из файла, который я могу исправить); и это о том, как я могу предотвратить потерю моего сеанса Emacs из-за преданности Emacs одному динамическому буферу.
Rekado
«Ну, мой вопрос не о отображении длинных строк». Тогда, возможно, вам следует сменить название. Возможно, вы хотите отфильтровать вывод низшего процесса и добавить новую строку после определенного количества символов?
няня
На самом деле, это имеет мало общего с длинными строками. yesв ansi-term, например , имеет аналогичный (но не , что ужасный) эффекта. На самом деле, это просто объем текста, который дает паузе emacs.
PythonNut
Вставка текста в буфер довольно быстрая, именно операции повторного отображения делают его медленнее, чем есть на самом деле. Честно говоря, работа yesв эмуляторе терминала VTE максимально использует все мои процессорные ядра, поэтому я бы не стал использовать его в качестве примера.
Васамаса

Ответы:

12

Как уже отвечали в комментариях, Emacs очень медленно перерисовывает длинные строки - это хорошо известная проблема . Исправить это было бы очень хорошо, но нужно много мыслей, чтобы быть правильно вытащил. У меня есть представление о том, как это можно сделать, основываясь на разделе 6.3 этого документа (в основном, храните информацию о визуальных строках в текущем буфере и обновляйте ее при вставке пробела, свойствах отображения, изменениях окна и т. Д., Затем используйте эту информацию в код повторного отображения, чтобы не сканировать его все время), но я недостаточно знаком с внутренними компонентами Си, чтобы выполнить его.

Хотя есть обходные пути. Наиболее очевидными из них будут настройка параметров, связанных с отображением (например, включение визуального усечения строки в графическом экземпляре 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 /in M-x shellне очень привлекательно (в идеале хотелось бы отображать только не укороченную строку, а не весь вывод), обнаружение строк в лучшем случае элементарно, и усечение можно было бы лучше обозначить с помощью эллипсов, а не осмысления всего. Кроме того, даже не гарантируется, что входящий текст не превращается в пакеты. Все это кричит о выполнении шага обработки во временном буфере, но будет оставлено читателю как упражнение (или автору как потенциальное сообщение в блоге).

wasamasa
источник
4

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

Полагается start-processи обрабатывает-отправляет-строку

Например, см. Функции py--start-fast-processиpy--fast-send-string-intern

Андреас Рёлер
источник