如何在Emacs中为任何模式显示ANSI颜色代码?

38

我有一个使用ANSI转义颜色代码格式化文本的日志文件。模式是fundamental。有其他已回答的问题涉及此问题,但我不确定如何将其应用于此模式或任何其他模式。我知道解决方案与以某种方式配置ansi-color有关。


https://github.com/atomontage/xterm-color - HappyFace
考虑到使用 emacs 时存在的限制/复杂性,你可能想尝试一种常见的替代方案来处理大型日志文件:less -R /path/to/file.log - Jeff Ward
5个回答

65
您可以使用以下代码。
(require 'ansi-color)
(defun display-ansi-colors ()
  (interactive)
  (ansi-color-apply-on-region (point-min) (point-max)))

然后您可以通过M-x执行display-ansi-colors,通过自己选择的键绑定或通过某些编程条件(也许您的日志文件具有与某些正则表达式匹配的扩展名或名称)来执行。

如果您想在只读缓冲区(日志文件、grep结果)中执行此操作,可以使用inhibit-read-only,因此函数将如下所示:

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

2
@ Avery,是的。另外,如果有其他人想知道如何做到这一点,将以下代码添加到你的 .emacs 文件中可以在所有 .log 文件上开启 ansi-color 显示(请根据你的文件扩展名进行选择):(add-to-list 'auto-mode-alist '("\\.log\\'" . display-ansi-colors)) - Son of the Wai-Pan
我正在尝试为我的 ack 结果(http://beyondgrep.com/)着色。结果缓冲区是只读的,这个解决方法不起作用。 - Gauthier
1
有没有一种方法可以在不修改文件的情况下执行此操作(例如处理转义序列并显示ANSI颜色)? - deb0ch
2
ansi-color-apply-on-region的效果很好,但似乎速度过慢(处理13000行区域需要30秒)。 - Curt
正如@lungang-fang在这里这里提到的,如果您使用的是emacs 28.2或更高版本,ansi-color-apply-on-region函数接受第三个参数"preserve-sequences"。因此,我们可以改进@juanleon的答案。 (interactive) (let ((inhibit-read-only t)) (ansi-color-apply-on-region (point-min) (point-max) t)))``` - undefined
显示剩余2条评论

10

用户自定义函数:

(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))

对于使用comint/compilation的缓冲区,请使用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))

8
Gavenkoa和Juanleon的解决方案对我有用,但它们修改了我正在读取的文件的内容,这并不令人满意。要在不修改文件内容的情况下进行着色,请下载tty-format.el并将以下内容添加到您的.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基于ansi-color.el,后者只在较新版本的emacs中原生地提供。


1
这对我有用,但是警告 - 不要尝试在大文件上执行此操作!我刚刚尝试了一个9兆日志文件,它锁定了emacs。 - adamc

1
在大文件上,ansi-color-apply-on-region 的性能较慢。这里提供了一种解决方案,可以对当前区域进行着色,并且可以在只读缓冲区中工作。
(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))))


唯一的缺点是 ansi-color-apply-on-region 会从缓冲区中删除 ANSI 转义序列字符,因此当您保存时,它们将丢失。我想知道是否有一种方法可以隐藏这些字符而不是剥离它们?

我正在使用emacs 28.2。ansi-color-apply-on-region现在包含第三个参数"preserve-sequences"。将其设置为"t"调用此函数可以实现您(和我)想要的效果。 - Lungang Fang
话虽如此,该函数的速度确实很慢。如果仅适用于可见区域,那就太好了。我知道许多模式/迷你模式都是这样工作的,比如linum(?) - Lungang Fang

1
对于这个任务,我定义了以下基于(require ansi-color)(emacs 28.2)的小模式。该小模式懒惰地运行`ansi-color-apply-on-region',即仅处理缓冲区中可见的部分。因此,即使日志文件很大,它也不会冻结Emacs。
(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)))


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接