Question

I have a log file that uses ANSI escape color codes to format the text. The mode is fundamental. There are other answered questions that address this issue but I'm not sure how to apply it to this mode or any other mode. I know the solution has something to do with configuring ansi-color in some way.

Was it helpful?

Solution

You could use code below

(require 'ansi-color)
(defun display-ansi-colors ()
  (interactive)
  (ansi-color-apply-on-region (point-min) (point-max)))

Then you can execute display-ansi-colors via M-x, via a key-binding of your choosing, or via some programmatic condition (maybe your log files have a extension or name that matches some regexp)

If you want to do this with read-only buffers (log files, grep results), you may use inhibit-read-only, so the function will be:

(defun display-ansi-colors ()
  (interactive)
  (let ((inhibit-read-only t))
    (ansi-color-apply-on-region (point-min) (point-max))))

OTHER TIPS

User defined function:

(defun my-ansi-color (&optional beg end)
  "Interpret ANSI color esacape sequence by colorifying cotent.
Operate on selected region on whole buffer."
  (interactive
   (if (use-region-p)
       (list (region-beginning) (region-end))
     (list (point-min) (point-max))))
  (ansi-color-apply-on-region beg end))

For buffers that uses comint/compilation use filter:

(ignore-errors
  (require 'ansi-color)
  (defun my-colorize-compilation-buffer ()
    (when (eq major-mode 'compilation-mode)
      (ansi-color-apply-on-region compilation-filter-start (point-max))))
  (add-hook 'compilation-filter-hook 'my-colorize-compilation-buffer))

Gavenkoa's and Juanleon's solutions worked for me, but were not satisfying as they were modifying the contents of the file I was reading.

To colorize without modifying the contents of the file, download tty-format.el and add the following to your .emacs:

(add-to-list 'load-path "path/to/your/tty-format.el/")

(require 'tty-format)

;; M-x display-ansi-colors to explicitly decode ANSI color escape sequences                                                                                                                                        
(defun display-ansi-colors ()
  (interactive)
  (format-decode-buffer 'ansi-colors))

;; decode ANSI color escape sequences for *.txt or README files                                                                                                                                                    
(add-hook 'find-file-hooks 'tty-format-guess)

;; decode ANSI color escape sequences for .log files                                                                                                                                                               
(add-to-list 'auto-mode-alist '("\\.log\\'" . display-ansi-colors))

tty-format is based on ansi-color.el which is only shipped natively with recent versions of emacs.

On large files, performance of ansi-color-apply-on-region is slow. Here's a solution that colors the current region and works with read-only buffers.

(require 'ansi-color)
(defun ansi-color-region ()
  "Color the ANSI escape sequences in the acitve region.
Sequences start with an escape \033 (typically shown as \"^[\")
and end with \"m\", e.g. this is two sequences
  ^[[46;1mTEXT^[[0m
where the first sequence says to diplay TEXT as bold with
a cyan background and the second sequence turns it off.

This strips the ANSI escape sequences and if the buffer is saved,
the sequences will be lost."
  (interactive)
  (if (not (region-active-p))
      (message "ansi-color-region: region is not active"))
  (if buffer-read-only
      ;; read-only buffers may be pointing a read-only file system, so don't mark the buffer as
      ;; modified. If the buffer where to become modified, a warning will be generated when emacs
      ;; tries to autosave.
      (let ((inhibit-read-only t)
            (modified (buffer-modified-p)))
        (ansi-color-apply-on-region (region-beginning) (region-end))
        (set-buffer-modified-p modified))
    (ansi-color-apply-on-region (region-beginning) (region-end))))

The one downside is that ansi-color-apply-on-region removes the ANSI escape sequence characters from the buffer, so when you save, they are lost. I wonder if there's a way to hide the characters instead of stripping them?

For this job, I defined the following minor mode which is based on (require ansi-color) (emacs 28.2). This minor mode runs `ansi-color-apply-on-region' lazily, i.e. only the visible part of the buffer. Hence, it does NOT freeze Emacs even if the log file is huge.

(defun ansi-color-after-scroll (window start)
  "Used by ansi-color-mode minor mode"
  (ansi-color-apply-on-region start (window-end window t) t))

(define-minor-mode ansi-color-mode
  "A very primitive minor mode to view log files containing ANSI color codes.

Pros: this minor mode runs `ansi-color-apply-on-region' lazily,
i.e. only the visible part of the buffer. Hence, it does NOT
freeze Emacs even if the log file is huge.

Cons: a) when the minor code is toggled off, it does not undo
what has already been ansi colorized. b) assumes the buffer
content etc. does not change. c) jumping to random places within
the buffer may incur incorrect/incomplete colorization.

How to install: put this code into your init.el, then evaluate it or
restart Emacs for the code to take effect.

How to use: in the log buffer of need run `M-x ansi-color-mode'.
Alternatively, feel free to enable this minor mode via mode hooks
so that you needn't enable it manually.

-- lgfang
"
  :global nil
  :lighter ""
  (if ansi-color-mode
      (progn 
        (ansi-color-apply-on-region (window-start) (window-end) t)
        (add-hook 'window-scroll-functions 'ansi-color-after-scroll 80 t))
    (remove-hook 'window-scroll-functions 'ansi-color-after-scroll t)))

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top