Terminal colour tolerance

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.

256 colour terminals

Using 256 colours in terminals is well-supported in GNU/Linux distributions these days, and also in Windows terminal emulators like PuTTY. Using 256 colours is great for Vim colorschemes in particular, but also very useful for Tmux colouring or any other terminal application where a slightly wider colour space might be valuable. Be warned that once you get this going reliably, there’s no going back if you spend a lot of time in the terminal.

Xterm

To set this up for xterm or emulators that use xterm as the default value for $TERM, such as xfce4-terminal or gnome-terminal, it generally suffices to check the options for your terminal emulator to ensure that it will allow 256 colors, and then use the TERM string xterm-256color for it.

An earlier version of this post suggested changing the TERM definition in .bashrc, which is generally not a good idea, even if bounded with conditionals as my example was. You should always set the terminal string in the emulator itself if possible, if you do it at all.

Be aware that older systems may not have terminfo definitions for this terminal, but you can always copy them in using a private .terminfo directory if need be.

Tmux

To use 256 colours in Tmux, you should set the default terminal in .tmux.conf to be screen-256color:

set -g default-terminal "screen-256color"

This will allow you to use color definitions like colour231 in your status lines and other configurations. Again, this particular terminfo definition may not be present on older systems, so you should copy it into ~/.terminfo/s/screen-256color on those systems if you want to use it everywhere.

GNU Screen

Similarly, to use 256 colours in GNU Screen, add the following to your .screenrc:

term screen-256color

Vim

With the applicable options from the above set, you should not need to change anything in Vim to be able to use 256-color colorschemes. If you’re wanting to write or update your own 256-colour compatible scheme, it should either begin with set t_Co=256, or more elegantly, check the value of the corresponding option value is &t_Co is 256 before trying to use any of the extra colour set.

The Vim Tips Wiki contains a detailed reference of the colour codes for schemes in 256-color terminals.