A Weird Imagination

256 color terminals

The problem

By default, terminals on Linux only use 8 colors (or 16 if setup to use bright variants instead of bold text). Everything else on a modern computer uses 24-bit color, allowing for millions of colors. More colors in the terminal would allow for better syntax highlighting and color output of various commands to be more readable.

In practice, while a few terminals support full 24-bit RGB color (at least Konsole does), it is not widespread enough to be used much. On the other hand, most terminals support 256 colors, which is significantly better than just 8.

Setting up 256 color terminals

Testing 256 color support

First, check if your terminal already supports 256 colors. You will probably want to rerun this check for confirming that you get 256 colors when connecting to another computer over ssh and/or inside a screen or tmux session if you use those programs. tput gives various information about the terminal, including how many colors it supports:

$ tput colors
256

The script 256colors2.pl linked from this guide on setting up 256 color terminals will attempt to display all of the colors, making it clear if your setup is actually displaying the colors correctly. For a pure shell solution which also displays the numbers, use

#!/bin/sh
for i in $(seq 0 255)
do
    printf '\033[1;38;5;%dmcolor %d\n' "$i" "$i"
done

Basic support

As your terminal program almost certainly supports 256 colors and is merely not telling the terminal about it, the fix is to correctly set the $TERM variable to announce 256 color support to the commands running in your terminal.

I did so in a very simple way by adding the following to by ~/.bashrc:

if [ -n "$DISPLAY" -a "$TERM" == "xterm" ]; then
    export TERM=xterm-256color
fi

The Fedora project's page on 256 color terminals includes a more comprehensive script that supports more terminal programs.

Those pages suggest that Debian/Ubuntu need the ncurses-term package in order for 256 color terminals to work properly, but that information is apparently out of date as I do not have that package installed.

When using ssh, the TERM variable of the client is visible to the server, so this should also make 256 color terminals work over ssh as long as the computers you are connecting to have the xterm-256color terminfo.

GNU Screen and Tmux

As GNU Screen and Tmux act like terminal emulators, they also need to be configured to support 256 colors. In my ~/.screenrc, simply added the following from here:

# enable 256 color support
term screen-256color

That makes screen always claim to its clients that it can display 256 colors. If it can't actually do so, it will map the colors down to the standard 8 color space. This does have the side effect of making the colors look a bit worse when using 8 color terminals due to color schemes for 256 colors being designed for closer colors being okay, but that's a minor problem because it's rare you will run across such a terminal (FingerTerm on my Nokia N9 is the only one I use).

In order to get GNU Screen to work properly, we had it claim to be GNU Screen with 256 color support. To get Tmux to work properly, we also have it claim to be GNU Screen with 256 color support.

Vim and CSApprox

At this point, all of your terminals should have 256 color support, including when nesting ssh and screen/tmux, but we haven't actually accomplished anything unless you really like looking at the color patterns output by 256colors2.pl.

To check if vim supports 256 colors, install xterm-color-table.vim (using Vundle) which adds the :XtermColorTable command to vim (it also works in gvim; make sure you are actually running console vim). I did not have to do anything special, but if it does not work for you, look into these workarounds.

You probably have color schemes that specify colors for GUI Vim in 24-bit color. Since our terminal is 256 colors, not 24-bit color, those cannot be used directly. The solution is CSApprox. CSApprox approximates 24-bit color with your terminal's available 256 colors, making console vim look almost as good as gvim.

How does it work?

Normally, terminals display whatever text is sent to them directly to the user. Not all characters are actually displayable, particularly control characters exist specifically to have special meanings outside of being shown directly to a user. Newlines and tabs are two of these special characters which tell the terminal to move the cursor to a different location instead of displaying a character immediately.

For more advanced commands, terminals support a whole range of ANSI escape codes which begin with the control character 0x1b (or \033 in octal) followed by [. Some of these commands are for changing the foreground or background color of text. From the script above

printf '\033[1;38;5;%dmcolor %d\n' "$i" "$i"

sets the color to $i (which replaces %d in the format string) because \033[ starts the escape sequence, 1; means to make it bold, and 38;5; is the code for setting a foreground color for a 256 color terminal, followed by the color number itself and then m terminates the command telling the terminal to interpret the rest of the string as normal text. Changing the 38 to 48 makes a command for setting the background color instead.

If you want to set colors for an 8-color terminal, the ANSI colours table on this page will show the proper code. It's a little more complicated because instead of having one command with an argument, each color is actually a separate command.

Comments

Have something to add? Post a comment by sending an email to comments@aweirdimagination.net. You may use Markdown for formatting.

There are no comments yet.