=====================================
Terminal Emulator 256 Color Support
=====================================
:Author: Trent Buck
:Date: 2007-09-10
:Abstract:
I use emacs in screen in urxvt on Debian (and Ubuntu). I worked
out how to get 256 color support working. This document describes
how.
Terminal emulator
======================================================================
At http://frexx.de/xterm-256-notes you can find a perl script by the
name of 256colors2.pl that generates the 256 color escape codes that
xterm implements. The second image on that page shows what the output
*should* look like if you run the script in a terminal that supports
256 colors. Be sure to run the script directly in the terminal
(rather than inside screen), because we haven't set up screen yet.
I tested a number of terminal emulators in Ubuntu Edgy for 256 color
support. Here are the results:
:yes: mrxvt pterm xterm konsole
:partial: rxvt-unicode
:no: aterm aterm-ml eterm gnome-terminal hanterm-xf mlterm
mrxvt-cjk mrxvt-mini multi-gnome-terminal powershell
rxvt-beta rxvt-ml tilda wterm wterm-ml xfce4-terminal xvt
According to http://bugzilla.gnome.org/168251, libvte (gnome-terminal,
xfce4-terminal) will support 256 colors Real Soon Now.
rxvt-unicode only supports 88 colours. Screen will accept 256 colours
from clients, and then use the nearest approximation of the 88 colours
under urxvt. The same principle applies when running screen (with 256
colour support) in an 8 colour or mono terminal.
Now that you know your terminal supports 256 colors, you need to make
sure that it is advertising the fact to clients. This is done with
the TERM environment variable. When an application starts, it looks
up the TERM value in the terminfo and/or termcap databases. You can
check what the terminfo database reports for the current TERM thusly::
tput colors # should print 256
xterm
------------------------------------------------------------
The xterm in Debian Lenny and Ubuntu Edgy does not advertise 256 color
support by default. To fix this you need to install a 256 color
terminfo entry, and tell xterm to use it::
aptitude install ncurses-term
echo XTerm.termName: xterm-256color \
>>~/.Xdefaults
xrdb -merge ~/.Xdefaults
Make sure .Xdefaults is loaded when you log in.
Screen
======================================================================
Screen's 256 color support is a compile-time option (see
http://bugs.debian.org/348099). If you use Etch/Edgy or older, you
must recompile it::
cd `mktemp -d`
echo deb-src http://archive.ubuntu.com/ubuntu edgy main \
>>/etc/apt/sources.list
aptitude update
apt-get build-dep screen
apt-get source screen
sed -i -e 'address@hidden/configure@& --enable-colors256@' \
screen-*/debian/rules
sed -i -e '1s/(\([^)]\+\))/(\1+256color)/' \
screen-*/debian/changelog
apt-get --build source screen
dpkg -i screen_*.deb
Like xterm, screen does not advertise 256 color support by default.
You must create a terminfo entry and tell screen to use it. The
following code places the compiled entry in ~/.terminfo, which is
searched by default. The entry below is based closely on the
xterm-256color entry from the ncurses-term package. I don't pretend
to understand how it works. ::
mkdir -p ~/.terminfo
cat >~/.terminfo/terminfo.src <>~/.screenrc
In theory screen's termcapinfo command can be used to advertise
different terminal properties (to programs running inside screen) on
the fly. Unfortunately it does not affect terminfo, only
termcap. Emacs doesn't look at termcap, so this command is useless.
Ideally we'd only set TERM to screen-256color if screen had been
compiled with --enable-256color, but there's apparently no way to
interrogate the screen binary to find this out programmatically.
Garry Dolley notes that on OS X 10.4, vim couldn't "see" the new
terminfo entry until he did ::
cd ~/.terminfo && mv s 73
Emacs
======================================================================
Emacs does not know how to handle the screen-256color terminfo
entry by default. From lisp/term/README:
When Emacs starts, it checks the TERM environment variable to see
what type of terminal the user is running on, checks for an elisp
file named term/${TERM}.el, and if one exists, loads it.
If that doesn't yield a file that exists, the last hyphen and what
follows it is stripped. If that doesn't yield a file that exists,
the previous hyphen is stripped, and so on until all hyphens are
gone.
So you need a file term/screen-256color.el in your load-path. Emacs
22 expects it to contain a terminal-init-screen defun. Emacs 21
expects it to contain a bunch of top-level forms. Here's what I use::
;;; This is for GNU Emacs 22
(defun terminal-init-screen ()
"Terminal initialization function for screen."
;; Use the xterm color initialization code.
(load "term/xterm")
(xterm-register-default-colors)
(tty-set-up-initial-frame-faces))
;;; This is for GNU Emacs 21
(if (= 21 emacs-major-version)
(load "term/xterm-256color"))
For Emacs 21, you also need to install the xterm-256color.el file from
http://www.splode.com/~friedman/software/emacs-lisp/src/term/xterm-256color.el
If xterm, screen and emacs are all set up correctly, ::
xterm -e screen emacs -nw -f list-colors-display
should have a lot of colors; not necessarily exactly 256, but
certainly more than sixteen.
Problems
======================================================================
I've been running the above setup for a few months, and it causes a
couple of niggling annoyances. Here's what they are, and what (if
anything) can be done about them.
Terminfo availability
------------------------------------------------------------
Whatever TERM value you use, the associated terminfo entry has to be
available everywhere you go. The 256 color entries are less likely to
be installed on esoteric systems, so you are likely to experience
problems using ssh and chroot. If you can't install the terminfo
entry, you have to degrade the TERM setting to something that *is*
supported, e.g. ::
TERM=screen ssh -t stupidhost screen emacs -nw
Screen degrades colors stupidly
------------------------------------------------------------
Programs running inside screen (with TERM set to screen-256color) will
always try to use 256 colors, even if screen itself is running in a
sixteen color terminal. This mostly works pretty well, because screen
automatically will degrade each of the 256 colors to the closest color
supported by the parent terminal.
The downside of this is that Screen isn't (and can't be) as smart
about handling color reduction. For example, in a sixteen color
terminal Emacs will use red and green for comments and strings
respectively. In a 256 color terminal, emacs uses chocolate and
salmon. But the closest approximation for *both* of those colors in a
sixteen color terminal is red, so when running emacs inside screen
inside a sixteen color terminal, you get red for both comments and
string.
There's really no way around this problem. For one thing, the
terminal's capabilities are transmitted by the TERM environment
variable, which can't be modified by a parent process. That is, if
you detach screen from a 256 color xterm and reattach in a sixteen
color xvt, there's no way for Screen to tell Emacs about this change.
The fact that screen's -x option allows you to view the same screen
window in both xterm and xvt at the same time only makes matters
worse.
This problem only matters if you run screen in a terminal that doesn't
support 256 colors; hopefully that won't happen very often.
Aptitude
------------------------------------------------------------
The aptitude bug http://bugs.debian.org/384699 affected 256-color
support in Sarge and Edgy. It is now fixed.