unix:256colours

See also:

Colour colour everywhere! 256 colour-mode for Linux consoles

My day-to-day work on computers involves Linux consoles, lots of them. At a minimum I have a console for the machine I am doing my work on, but typically I'll be working across 3 or more hosts (my Windows workstation, my Linux workstation, a server I admin, the local cluster and a remote cluster), and almost certainly have more than one shell open per host.

I mention all this because it means I have a lot of shells around, too many to have one per window! Rather, I use GNU screen to “tab” my shells together, leaving me with one window per host that has a tab for each shell.

Because most of my work is done on remote (headless) machines via SSH the most convenient way to work with, well, anything is via text-only interfaces. For this reason, among others, vim is my preferred editor.

I like colourful syntax highlighting, and vim provides it. But only 16 colours in most terminals. It turns out this is usually because of poor configuration - most mainstream terminal emulators (PuTTY / xterm / gnome-terminal / rvxt…) support 256 colours, but you have to enable it and/or let your applications know about it capabilities.

So, does terminal <insert name here> do 256 colours?

See http://www.frexx.de/xterm-256-notes/ for some scripts which produce test patterns. Just in case that site disappears, I'll reproduce the script and screen shot here:

The Perl script: 256colors2.pl

What you will see if your terminal supports 256 colours:

Expected output from 256colors2.pl

And here's what you'll see if it doesn't:

16-colour mode output from 256colors2.pl

Make sure you are running these scripts directly in your terminal - don't start them from within screen or any other kind of “manager” that might interpret / translate output.

If you use PuTTY, then be sure to tick “Allow terminal to use xterm 256-color mode” under Settings → Window → Colours

OK, it does. Now how about Vim?

See :help xterm-color for the official documentation. It makes mention of 256 colours, but isn't hugely helpful.

New versions of Vim come with a colour-test script you can run. Start Vim and enter the following command:

:runtime syntax/colortest.vim

Chances are that the first time you do this your “red” and “lightred” will look identical. Try telling Vim that your terminal supports 256 colours:

:let &t_Co=256

And then rerun the colour test. If all goes well you're output will look like this:

Successful 256 colour test in Vim

Getting Vim to use all colours without hard-coding it

Chances are your $TERM environment variable is set to xterm. Try setting it to xterm-256color (remember to export it) and try again:

export TERM=xterm-256color
vim "+runtime syntax/colortest.vim"

If you get an error about unknown terminal, or unknown terminal capabilities, try installed the ncurses-term package. It contains terminal definitions which intelligent programs can use to determine the exact capabilities of a terminal named by the $TERM environment variable. On Debian-based distros:

sudo apt-get install ncurses-term

You may need to open a new terminal for this to have an effect.

Setting TERM=xterm-256color by default

For PuTTY, you can change what TERM name it sends under Settings → Connection → Data → “Terminal-type string”. Change it to xterm-256colors, done!

For gnome-terminal, the default Ubuntu terminal if you didn't customise your install, you can't change what it reports itself as: xterm. My work around for this was to add the following snippet to my ~/.bashrc:

if [ "$TERM" == "xterm" ]; then
    # No it isn't, it's gnome-terminal
    export TERM=xterm-256color
fi

Recap: The story so far

In case this is getting confusing here's what's been covered so far:

  1. Checking your terminal can display 256 colour text
  2. Checking Vim can make use of these colours by setting TERM=xterm-256color
    • Possibly installing a support package so that so is a meaningful name
  3. Configuring the terminal to report it's xterm-256color, or using login-scripts to change the reported name as a work-around.

So at this point you should be able to open a new terminal, run vim ”+runtime syntax/colortest.vim” and see 256 color mode working.

And finally, keeping it working under GNU screen

Now, unless you're extra-ordinarily lucky, running GNU screen will prevent 256 colors working. This is often because screen is compiled without 256-colour support on most distros.

Run-time configuration

But before diving into recompiling we should update screen's configuration file so that we can be sure it's doing the right thing. Create/modify ~/.screenrc and add the following lines to it:

# Enable 256-color mode when screen is started with TERM=xterm-256color
# Taken from: http://frexx.de/xterm-256-notes/
#
# Note that TERM != "xterm-256color" within a screen window. Rather it is
# "screen" or "screen-bce"
# 
# terminfo and termcap for nice 256 color terminal
# allow bold colors - necessary for some reason
attrcolor b ".I"
# tell screen how to set colors. AB = background, AF=foreground
termcapinfo xterm-256color 'Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm'

And then (re)start screen and try the 256color2.pl test script. If it doesn't work, and you're sure that TERM=xterm-256color when you start screen and that it's being exported1), you need to recompile screen with 256-color support.

Compile-time configuration

Here's a quick-and-dirty guide on how to recompile it on Ubuntu, see Debian's source-packages HOWTO guide for more detail.

sudo apt-get build-dep screen                 # Install whatever's needed to compile screen
apt-get source screen                        # Download + extract screen source
cd ./screen-4.0.3
./configure --help | grep 256                 # Find magic option we need
vim debian/rules                              # Edit package build rules, and add \
                                              # --enable-colors256 to the ./configure command line
fakeroot dpkg-buildpackage -uc -b             # Create a *.deb package file in the directory above current
cd ..
sudo dpkg -i screen_4.0.3-7ubuntu1_i386.deb   # Install the newly create package

Now the 256color2.pl script should produce pretty colours even in screen. But Vim might not.

Vim under screen refuses to conform!

In my experience this is because screen sets some environment variables when it starts. In particular, TERM=screen. This of course prevents Vim from knowing that 256-colour mode is supported. I experimented with overriding this and setting it back to TERM=xterm-256color, but that seemed to break lots of other apps, such as aptitude. It did fix Vim though.

Another problem is that screen sets TERMCAP with a colours (Co) entry set to just 8, not 256. See for yourself:

echo $TERMCAP | sed -e 's/:/\n/g' | grep Co  # Prints 'Co#8'

TERMCAP is a list of colon-seperated capabilities for the current terminal. Newer distros prefer to use a system-wide terminfo database, which allow applications to lookup, say, xterm-256color (the name of a terminal) though an API and discover it's full list of capabilities; including that it supports 256-colors.

But TERMCAP is still supported, and when defined it appears to take precedence over terminfo. At least it does with Vim.

So it would appear the correct solution is: Leave TERM=screen alone and mangle the TERMCAP variable so that its Co entry is set to 256, and export it:

export TERMCAP=$(echo $TERMCAP | sed -e 's/Co#8/Co#256/g')

…and make sure Vim uses the TERMCAP settings by adding this to ~/.vimrc:

" Work-around incomplete terminfo databases                                     
" Particulalry useful when under `screen`, which may or may not be attached to  
" a physical terminal capable of 256color mode.                                 
if match($TERMCAP, 'Co#256:') == 0 || match($TERMCAP, ':Co#256:') > 0           
    set t_Co=256                                                                
endif    

This will make Vim check if TERMCAP contains a Co#256 entry (either at the beginning or elsewhere) and set 256-colour mode accordingly.

Now run Vim and its colour test again, and you should get all the colours!

Making the TERMCAP mangling automatic

This is what ~/.bashrc is for!

if [ ! -z "$TERMCAP" ] && [ "$TERM" == "screen" ]; then                         
    export TERMCAP=$(echo $TERMCAP | sed -e 's/Co#8/Co#256/g')                  
fi 
1) TERM=xterm-256color sets it for the current shell, but only the current shell. Child processes will not see it. To cause child processes to see it it must be 'exported' with the 'export' command. E.g.: TERM=xterm-256color; export TERM or shotcut with export TERM=xterm-256color
unix/256colours.txt · Last modified: 2009/08/21 13:17 by robm