Changing Text Color

Problem

You want to display multicolored text on the console.

Solution

The simplest solution is to use HighLine. It lets you enclose color commands in an ERb template that gets interpreted within HighLine and printed to standard output. Try this colorful bit of code to test the capabilities of your terminal:

require ubygems require highline/import say(%{Heres some <%= color(dark red text, RED) %>.}) say(%{Heres some <%= color(right red text on a blue background, RED+BOLD+ON_BLUE) %>.}) say(%{Heres some <%= color(linking bright cyan text, CYAN+BOLD+BLINK) %>.}) say(%{Heres some <%= GREEN+UNDERLINE %>underlined dark green text<%=CLEAR%>.})

Some of these features (particularly the blinking and underlining) aren supported on all terminals.

Discussion

The HighLine#color method encloses a display string in special command strings, which start with an escape character and a left square bracket:

HighLine.new.color(Hello, HighLine::GREEN) # => "e[32mHelloe[0m"

These are ANSI escape sequences. Instead of displaying the string "e[32m", an ANSI-compatible terminal treats it as a command: in this case, a command to start printing characters in green-on-black. The string "e[0m" tells the terminal to go back to white-on-black.

Most modern Unix terminals support ANSI escape sequences, including the Mac OS X terminal. You should be able to get green text in your irb session just by calling puts "e[32mHelloe[0m" (try it!), but HighLine makes it easy to get color without having to remember the ANSI sequences.

Windows terminals don support ANSI by default, but you can get it to work by loading ANSI.SYS (see below for a relevant Microsoft support article).

An alternative to HighLine is the Ncurses library.[4] It supports color terminals that use a means other than ANSI, but these days, most color terminals get their color support through ANSI. Since Ncurses is much more complex than HighLine, and not available as a gem, you should only use Ncurses for color if you e already using it for its other features.

[4] Standard Curses doesn support color because it was written in the 1980s, when monochrome ruled the world.

Heres a rough equivalent of the HighLine program given above. This program uses the Ncurses::program wrapper described in Recipe 21.5. The wrapper sets up Ncurses and initializes some default color pairs:

Ncurses.program do |s| # Define the red-on-blue color pair used in the second string. # All the default color pairs use a black background. Ncurses.init_pair(8, Ncurses::COLOR_RED, Ncurses::COLOR_BLUE) Ncurses::attrset(Ncurses::COLOR_PAIR(1)) s.mvaddstr(0,0, "Heres some dark red text.") Ncurses::attrset(Ncurses::COLOR_PAIR(8) | Ncurses::A_BOLD) s.mvaddstr(1,0, "Heres some bright red text on a blue background.") Ncurses::attrset(Ncurses:: COLOR_PAIR(6) | Ncurses::A_BOLD | Ncurses::A_BLINK) s.mvaddstr(2,0, "Heres some blinking bright cyan text.") Ncurses::attrset(Ncurses::COLOR_PAIR(2) | Ncurses::A_UNDERLINE) s.mvaddstr(3,0, "Heres some underlined dark green text.") s.getch end

An Ncurses program can draw from a palette of color pairscombinations of foreground and background colors. Ncurses::program sets up a default palette of the seven basic ncurses colors (red, green, yellow, blue, magenta, cyan, and white), each on a black background. You can change this around if you like, or define additional color pairs (like the red-on-blue defined in the example). The following Ncurses program prints out a color chart of all foreground-background pairs. It makes the text of the chart bold, so that the text doesn become invisible when the background is the same color.

Ncurses.program do |s| pair = 0 Ncurses::COLORS.each_with_index do |background, i| Ncurses::COLORS.each_with_index do |foreground, j| Ncurses::init_pair(pair, foreground, background) unless pair == 0 Ncurses::attrset(Ncurses::COLOR_PAIR(pair) | Ncurses::A_BOLD) s.mvaddstr(i, j*4, "#{foreground},#{background}") pair += 1 end end s.getch end

You can modify a color pair by combining it with an Ncurses constant. The most useful constants are Ncurses::A_BOLD, Ncurses::A_BLINK, and Ncurses::A_UNDERLINE. This works the same way (and, on an ANSI system, uses the same ANSI codes) as HighLines BOLD, BLINK, and UNDERLINE constants. The only difference is that you modify an Ncurses color with the OR operator (|), and you modify a HighLine color with the addition operator.

See Also

Категории