6

I have a buffer with terminal escape codes in it and I want them to be colored:

screenshot of buffer with raw escape codes

I was able to do this with (ansi-color-apply-on-region (point-min) (point-max)):

screenshot of buffer with colored escape codes

However, my file is really big and that command is really slow. Is there any mode that colors terminal escape codes with font lock? I imagine that would be much faster.

NOTE: What I am looking at is a log file, not a shell buffer, so solutions involving M-x shell output are irrelevant to me.

5
  • 1
    "Is there any mode that colors terminal escape codes with font lock? I imagine that would be much faster." Converting ansi color escape codes to font-lock-face properties so that font-lock will show the colours is precisely what ansi-color-apply is doing.
    – phils
    Commented Jun 26, 2018 at 21:23
  • 1
    @phils, is there a minor or major mode based on ansi-color-apply? In the question it looks like the entire buffer is converted at once, which is time consuming for large buffers. Normally, font-lock rules are only applied to the visible part of a buffer which makes them much faster. Commented Jun 27, 2018 at 4:37
  • @Lindydancer, I don't know, but is the font-lock system capable of editing/filtering buffer text beyond the text properties / faces? ansi-color-apply deletes the ansi escape code characters from the text and adds text properties in their place. I didn't think that was a task for which font-lock was suitable, but you'll know much better than I do.
    – phils
    Commented Jun 27, 2018 at 5:16
  • @phils, to make a font-lock package out of this, it would be much better to hide the ANSI sequences using the invisible text property without altering the actual text. In addition, ANSI sequences stretching over multiple lines may be problematic, since font-lock only highlights one or a few lines at a time. Commented Jun 27, 2018 at 15:33
  • n.b. npostavs' answer has made me realise that ansi-color-apply and ansi-color-apply-on-region do things very differently! The former puts font-lock-face text properties on the string, while the latter creates overlays and places face properties on those.
    – phils
    Commented Jun 27, 2018 at 20:58

2 Answers 2

1

If you set up your shell buffer to convert the escape codes to color automatically, it works much faster. I have the following config:

(add-to-list 'comint-output-filter-functions 'ansi-color-process-output)
(ansi-color-for-comint-mode-on)

With this set, when I run a shell in emacs (i.e., M-x shell), the output is colored automatically each time it is produced. That means you only wait an undetectable short period for emacs to color each line of output, rather than waiting for the entire buffer to be colored like you're experiencing.

8
  • This isn’t a shell buffer, it’s a log file. Commented Jun 26, 2018 at 20:18
  • I'd be tempted to try M-x shell, then call cat <logfile> to see if that's faster than what you've done
    – Tyler
    Commented Jun 26, 2018 at 22:44
  • 1
    That would probably work as a workaround for my problem, but for the sake of providing the “best” answer for this question, I’d like to be able to open the file using find-file and it “just works.” Commented Jul 18, 2018 at 19:23
  • Sure, no problem. Did you try it? If it does work, that would give us a clue for coming up with a solution that 'just works' with find-file.
    – Tyler
    Commented Jul 18, 2018 at 19:37
  • cat in M-x shell provides color output even without your ELisp snippet. However, I think that trick is irrelevant to solving this question the “right” way, because it runs into the same problem I posed in my question, i.e. cat results in coloring an entire enormous file. I also don’t want to view the file in shell-mode, I want to view it in fundamental-mode. Commented Jul 18, 2018 at 19:56
1

I was able to do this with (ansi-color-apply-on-region (point-min) (point-max)):

However, my file is really big and that command is really slow.

That function uses overlays by default, which will quickly become very slow when you have many of them. Try

(let ((ansi-color-apply-face-function
       (lambda (beg end face)
         (when face
           (put-text-property beg end 'face face)))))
  (ansi-color-apply-on-region (point-min) (point-max)))

See also

1
  • 1
    I tested this on a 70 MB log file and it took about 30 seconds, freezing Emacs in the process. Better, but still less-than-ideal. Commented Jul 18, 2018 at 20:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.