Skip to content


Switch branches/tags


Failed to load latest commit information.
Latest commit message
Commit time

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.


  • 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


Simple and most flexible method:

;; 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.

Alternatively, you can install through MELPA or some other Emacs package manager.


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.


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

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

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.


An example configuration for eshell:

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

Compilation buffers

For standalone compilation buffers use the following configuration:

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

NOTE: This compilation-mode configuration will break ag.el and 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 already exist.


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


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


M-x xterm-color-test

For comint or eshell:

M-x shell || M-x eshell

perl tests/xterm-colortest && perl tests/

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

img/xterm-color-thumb.png img/godwars2-thumb.png img/wttr-thumb.png


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


xristos (AT) sdf (DOT) org