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.

  • 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 Jun 26 '18 at 21:23
  • @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. – Lindydancer Jun 27 '18 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 Jun 27 '18 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. – Lindydancer Jun 27 '18 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 Jun 27 '18 at 20:58

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)

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.

| improve this answer | |
  • This isn’t a shell buffer, it’s a log file. – Jackson Jun 26 '18 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 Jun 26 '18 at 22:44
  • 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.” – Jackson Jul 18 '18 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 Jul 18 '18 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. – Jackson Jul 18 '18 at 19:56

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

| improve this answer | |
  • 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. – Jackson Jul 18 '18 at 20:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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