As already answered in the comments, Emacs becoming very slow in its
redisplay for long lines is a well-known
issue. Fixing it
would be very nice, but needs lots of thought to be pulled off
correctly. I have an idea of how it could be accomplished based on
section 6.3 of this
document
(basically, store visual line information in the current buffer and
update it on insertion of whitespace, display properties, window
changes, etc., then use that information in the redisplay code to
avoid scanning for it all the time), but am not familiar enough with
the C internals to pull it off.
There are workarounds though. The most obvious ones would be tuning
display-related parameters (like, enabling visual line truncation in
the graphical Emacs instance, using a non-graphical Emacs to have that
done automatically, disabling Bidi features, etc.) and preprocessing
the file contents you're reading in. A less obvious one is
automatically post-processing the files, be it by actually truncating
their lines or adding text properties that make the lines appear
shorter than they actually are. To turn this into a more interesting
answer, I'll present a pretty ugly hack of the former option that will
only work for comint
-derived modes:
(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)
This defines my-comint-shorten-long-lines
, a function that takes a
string possibly consisting of many lines and uses the power of regular
expressions to replace any line in it with a length of 80 characters
or more with a shortened version that displays the original text when
hovering over it. When used as hook in
comint-preoutput-filter-functions
it will filter all comint
output
before it's displayed.
However, this rendition of the hack has a pretty serious weakness. In
modes that have basic fontification going on (like, M-x ielm
), it
will happily cut off lines that are part of a string and will that way
fontify everything until the next quote as string! That's not what we
want and can be fixed with a bit more regex mastery (but will
presumably break inside a REPL for a language like Python).
While we're at it, let's highlight shortened output, too:
(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)
That's a bit better, but still ugly. Hovering on the output of
something like find /
in M-x shell
is not appealing (we'd ideally
want only to display the unshortened line, not all output), string
detection is rudimentary at best and truncation could be indicated
better with ellipses instead of fontifying everything. On top of
that, it's not even guaranteed that the text coming in isn't turned
into batches. All of this screams for doing the processing step in a
temporary buffer, but will be left for the reader as exercise (or the
author as potential blog post).