xterm-color icon indicating copy to clipboard operation
xterm-color copied to clipboard

ANSI & xterm-256 color text property translator for Emacs

[[https://opensource.org/licenses/BSD-2-Clause][https://img.shields.io/badge/license-BSD-blue.svg]] [[https://melpa.org/#/xterm-color][https://melpa.org/packages/xterm-color-badge.svg]] [[http://stable.melpa.org/#/xterm-color][https://stable.melpa.org/packages/xterm-color-badge.svg]]

xterm-color.el is an ANSI control sequence to text-property translator.

Translation takes place through state machine emulation which provides a far more accurate, comprehensive result than ansi-color.el that is built-into Emacs, without compromising on performance.

  • Features
  • Regular ANSI color support
  • XTERM 256 color support
  • Truecolor (24-bit) support
  • AIXTERM bright foreground color
  • AIXTERM bright background color (since 1.8)
  • Use bold instead of bright (since 1.8)
  • When colorizing entire buffers, optional overlay support (since 2.0)
  • Optionally, filter out ANSI control sequences (since 2.0)
  • Works with compilation-mode
  • Works with eshell
  • Install Simple and most flexible method:

#+BEGIN_SRC emacs-lisp ;; Clone this repository, ensure directory of xterm-color.el is in your ;; load-path and add the following to your init file: (require 'xterm-color)

;; You should byte-compile xterm-color.el for maximum performance. #+END_SRC

Alternatively, you can install through [[https://melpa.org/][MELPA]] or some other Emacs package manager.

  • Usage Interactively or from Emacs Lisp, call ~xterm-color-colorize-buffer~ to colorize an entire buffer.

You may customize ~xterm-color-debug~ (default nil, if non-nil you will get warnings in Messages when unsupported escape sequences are encountered), ~xterm-color-use-bold-for-bright~ (default nil), ~xterm-color-names~, ~xterm-color-names-bright~. Additionally, you may set ~xterm-color-preserve-properties~ to t (default nil, should be set to t only if using xterm-color with eshell, see below).

If you want to filter out all ANSI control sequences, without applying them to the text, set ~xterm-color-render~ to nil.

A buffer-local face attribute cache is used since 1.8 to improve performance. This means that if changes are made to ~xterm-color-names~ or ~xterm-color-names-bright~ or ~xterm-color-use-bold-for-bright~ at runtime, ~xterm-color-clear-cache~ should be called in a buffer with activated xterm-color for changes to take effect in that buffer.

** Comint You can replace ansi-color.el with xterm-color for all comint buffers, but you should take into account modes that propertize strings and pass them through ~comint-preoutput-filter-functions~ since ~xterm-color-filter~ will strip all text properties (this is done to get maximum performance). The recommended configuration that avoids issues is to remove ~ansi-color-process-output~ from ~comint-output-filter-functions~ and add ~xterm-color-filter~ as the first hook in the buffer-local ~comint-preoutput-filter-functions~ for any comint-based mode that you would like it to affect (e.g. shell-mode).

Additionally, it is recommended to disable font-locking for shell-mode buffers [[https://github.com/atomontage/xterm-color/issues/28][since it interacts badly with comint and drastically affects performance]]. Font locking in shell-mode buffers is superfluous since xterm-color.el will handle faces fine by itself.

Example configuration for shell-mode (M-x shell):

#+BEGIN_SRC emacs-lisp (setq comint-output-filter-functions (remove 'ansi-color-process-output comint-output-filter-functions))

(add-hook 'shell-mode-hook (lambda () ;; Disable font-locking in this buffer to improve performance (font-lock-mode -1) ;; Prevent font-locking from being re-enabled in this buffer (make-local-variable 'font-lock-function) (setq font-lock-function (lambda (_) nil)) (add-hook 'comint-preoutput-filter-functions 'xterm-color-filter nil t)))

;; Also set TERM accordingly (xterm-256color) in the shell itself. #+END_SRC

Using ~compilation-shell-minor-mode~ (NOTE: not the same as compilation-mode) with shell-mode buffers that have xterm-color enabled is NOT recommended, as ~compilation-shell-minor-mode~ depends on font-locking and causes severe performance degradation. Omit the statements that disable font-locking in the shell-mode example configuration if you need it.

** Eshell An example configuration for eshell:

#+BEGIN_SRC emacs-lisp (require 'eshell) ; or use with-eval-after-load

(add-hook 'eshell-before-prompt-hook (lambda () (setq xterm-color-preserve-properties t)))

(add-to-list 'eshell-preoutput-filter-functions 'xterm-color-filter) (setq eshell-output-filter-functions (remove 'eshell-handle-ansi-color eshell-output-filter-functions)) (setenv "TERM" "xterm-256color") #+END_SRC

** Compilation buffers For standalone compilation buffers use the following configuration:

#+BEGIN_SRC emacs-lisp (setq compilation-environment '("TERM=xterm-256color"))

(defun my/advice-compilation-filter (f proc string) (funcall f proc (xterm-color-filter string)))

(advice-add 'compilation-filter :around #'my/advice-compilation-filter) #+END_SRC

NOTE: This compilation-mode configuration will break [[https://github.com/Wilfred/ag.el][ag.el]] and [[https://github.com/dajva/rg.el][rg.el]], since these packages expect ANSI control sequences to be part of compilation output so that they can be used for matching. Suggestions for these packages to improve the way they perform matching [[https://github.com/dajva/rg.el/issues/65][already]] [[https://github.com/atomontage/xterm-color/issues/37][exist]].

** Other For programmatic usage from Emacs Lisp, call ~xterm-color-filter~ to propertize strings that you can then insert into a buffer. All state is kept in buffer-local variables which means that control sequences can span ~xterm-color-filter~ calls (state machine processing).

Example:

#+BEGIN_SRC emacs-lisp (let ((buffer (generate-new-buffer "xterm-color-test"))) (with-current-buffer buffer (insert (xterm-color-filter "\x1b[0;1;3;4")) (insert (xterm-color-filter ";35")) (insert (xterm-color-filter ";51mThis is only a test")) (insert (xterm-color-filter "\x1b[0m"))) (switch-to-buffer buffer)) #+END_SRC

  • Test #+BEGIN_SRC emacs-lisp M-x xterm-color-test

For comint or eshell:

M-x shell || M-x eshell

perl tests/xterm-colortest && perl tests/256colors2.pl

printf "\x1b[0;1;3;4;35;51mThis is only a test\x1b[0m\n"

Comparison with ansi-color.el:

M-x xterm-color-test-raw then M-x xterm-color-colorize-buffer

and contrast with

M-x xterm-color-test-raw then M-: (ansi-color-apply-on-region (point-min) (point-max))

#+END_SRC

[[file:img/xterm-color.png][file:img/xterm-color-thumb.png]] [[file:img/godwars2.png][file:img/godwars2-thumb.png]] [[file:img/wttr.png][file:img/wttr-thumb.png]]

  • License The code comes with a BSD-style license so you can basically do with it whatever you want.

  • Author xristos (AT) sdf (DOT) org