Using 256 colour terminals with applications like Vim and tmux is pretty much a no-brainer; it’s been well-supported on most GUI terminal emulators for ages, including Windows emulators like PuTTY, and gives you a much wider spectrum of colour with which to work and to apply useful features like syntax highlighting and contextual colours for shell prompts.
The problem is that not all terminals are created equal. Occasionally, you’ll
find yourself needing to use a console, perhaps with the linux
type, when
your X server doesn’t start or you’re using a KVM. Following the principles of
graceful degradation, it’s a good idea to arrange your terminal
configuration and any other applications that normally take advantage of the
wider 256 colour spectrum to start up normally with no errors, and to use
sensible values instead as supported by the terminal.
Bash
You can check the number of colours supported by your $TERM
setting using the
tput
command:
$ tput colors
256
On systems using termcap
, the syntax is slightly different:
$ tput Co
256
This provides you with an accessible way to set up graceful degradation for any
colours that you use in your .bashrc
file or other startup scripts. By way of
example, in my .bashrc
file I include the following stanza that adjusts the
colour of my prompt depending on whether I have root privileges:
if ((EUID == 0)); then
PS1=${color_root}${PS1}${color_undo}
else
PS1=${color_user}${PS1}${color_undo}
fi
The variables contain the terminal escape codes used to start painting text in
appropriate colours for the terminal type. I set these earlier on in the file
by checking the output of tput colors
:
colors=$(tput colors)
# Terminal supports 256 colours
if ((colors >= 256)); then
color_root='\[\e[38;5;9m\]'
color_user='\[\e[38;5;10m\]'
color_undo='\[\e[0m\]'
# Terminal supports only eight colours
elif ((colors >= 8)); then
color_root='\[\e[1;31m\]'
color_user='\[\e[1;32m\]'
color_undo='\[\e[0m\]'
# Terminal may not support colour at all
else
color_root=
color_user=
color_undo=
fi
The above conditional restricts the colour space to conform to what the terminal explicitly specifies is supported. If no colours at all are supported, the variables are empty, and the prompt is simply printed with no colour at all.
Vim
A familiar structure from a lot of Vim colorscheme
definition files is:
if has("gui_running") || &t_Co >= 256
...
endif
This has the effect of checking that either gVim is running, or that the terminal is capable of printing 256 colours. You can therefore use this and similar structures to delineate different sections of the file to apply based on the number of colours supported by the terminal.
if has("gui_running") || &t_Co >= 256
...
elseif &t_Co >= 88
...
elseif &t_Co >= 8
...
endif
It’s not really a good idea to define this sort of stuff in your .vimrc
file;
colour information should go into your colour scheme file.
Tmux
Things are a little tricker in tmux. Conditionals based on shell output are
supported in recent versions. If you have a particular line of your
configuration that will only work on terminals that support a certain number of
colours, you can prefix that line with an #if-shell
call:
if-shell 'test $(tput colors) -ge 256' 'set-option -g default-terminal "screen-256color"'
The above will only set the default terminal to screen-256color
for new
sessions if the test
call returns a result greater than or equal to 256. Note
that you need to wrap both the shell test and the configuration to run in
quotes for this to work.
You can preface every applicable line with this test, or if you’d prefer to only run one test for efficiency reasons, you could arrange to load a separate local configuration file only if a single test passes:
if-shell 'test "$(tput colors)" -ge 256' 'source-file ~/.tmux.256.conf'
Unfortunately, there’s a race condition in tmux that means that the first
shell can be established before the default-terminal
configuration item is
actually applied, meaning that the default $TERM
of screen
is used for the
first window, but subsequent windows are correctly created with the
screen-256color
setting for $TERM
. One possible workaround for this is to
preserve the old terminal’s name in an environment variable:
containing_term=$TERM
if-shell 'test "$(tput colors)" -ge 256' 'set-option -g default-terminal "screen-256color"'
You can then check this variable’s value in your .bashrc
file to see if it’s
a terminal known to support 256 colours, and if it is, force the
screen-256color
terminal type for the shell:
case $containing_term in
*256color)
TERM=screen-256color
unset containing_term
;;
esac
This problem may well be fixed in future versions of tmux, but it still seems to be an issue even in the developing 1.7 version.
All of the above goes a long way to making your personal set of dotfiles more robust, so that when you need to bust them out on some older machine or less capable terminal, they’re more likely to work properly.