Overview

Blessed provides just one top-level object: Terminal. Instantiating a Terminal figures out whether you’re on a terminal at all and, if so, does any necessary setup:

>>> term = Terminal()

After that, you can proceed to ask it all sorts of things about the terminal, such as its size:

>>> term.height, term.width
(34, 102)

Its color support:

>>> term.number_of_colors
256

And use construct strings containing color and styling:

>>> term.green_reverse('ALL SYSTEMS GO')
'\x1b[32m\x1b[7mALL SYSTEMS GO\x1b[m'

Furthermore, the special sequences inserted with application keys (arrow and function keys) are understood and decoded, as well as your locale-specific encoded multibyte input, such as utf-8 characters.

Styling and Formatting

Lots of handy formatting codes are available as attributes on a Terminal class instance. For example:

from blessed import Terminal

term = Terminal()

print('I am ' + term.bold + 'bold' + term.normal + '!')

These capabilities (bold, normal) are translated to their sequences, which when displayed simply change the video attributes. And, when used as a callable, automatically wraps the given string with this sequence, and terminates it with normal.

The same can be written as:

print('I am' + term.bold('bold') + '!')

You may also use the Terminal instance as an argument for the str.format`() method, so that capabilities can be displayed in-line for more complex strings:

print('{t.red_on_yellow}Candy corn{t.normal} for everyone!'.format(t=term))

Capabilities

Capabilities supported by most terminals are:

bold

Turn on ‘extra bright’ mode.

reverse

Switch fore and background attributes.

blink

Turn on blinking.

normal

Reset attributes to default.

underline

Enable underline mode.

Note that, while the inverse of underline is no_underline, the only way to turn off bold or reverse is normal, which also cancels any custom colors.

Many of these are aliases, their true capability names (such as ‘smul’ for ‘begin underline mode’) may still be used. Any capability in the terminfo(5) manual, under column Cap-name, may be used as an attribute of a Terminal instance. If it is not a supported capability for the current terminal, or a non-tty is used as output stream, an empty string is always returned.

Colors

XXX TODO XXX

all X11 colors are available, rgb(int, int, int), truecolor is automatically detected, or, downsampled to 256 or 16, 8, etc colorspace.

Color terminals are capable of at least 8 basic colors.

  • black

  • red

  • green

  • yellow

  • blue

  • magenta

  • cyan

  • white

The same colors, prefixed with bright_ (synonymous with bold_), such as bright_blue, provides 16 colors in total.

Prefixed with on_, the given color is used as the background color. Some terminals also provide an additional 8 high-intensity versions using on_bright, some example compound formats:

from blessed import Terminal

term = Terminal()

print(term.on_bright_blue('Blue skies!'))

print(term.bright_red_on_bright_yellow('Pepperoni Pizza!'))

You may also specify the color() index by number, which should be within the bounds of value returned by number_of_colors:

from blessed import Terminal

term = Terminal()

for idx in range(term.number_of_colors):
    print(term.color(idx)('Color {0}'.format(idx)))

You can check whether the terminal definition used supports colors, and how many, using the number_of_colors property, which returns any of 0, 8 or 256 for terminal types such as vt220, ansi, and xterm-256color, respectively.

Colorless Terminals

If the terminal defined by the Environment variable TERM does not support colors, these simply return empty strings. When used as a callable, the string passed as an argument is returned as-is. Most sequences emitted to a terminal that does not support them are usually harmless and have no effect.

Colorless terminals (such as the amber or green monochrome vt220) do not support colors but do support reverse video. For this reason, it may be desirable in some applications to simply select a foreground color, followed by reverse video to achieve the desired background color effect:

from blessed import Terminal

term = Terminal()

print(term.green_reverse('some terminals standout more than others'))

Which appears as black on green on color terminals, but black text on amber or green on monochrome terminals. Whereas the more declarative formatter black_on_green would remain colorless.

Note

On most color terminals, bright_black is not invisible – it is actually a very dark shade of grey!

Compound Formatting

If you want to do lots of crazy formatting all at once, you can just mash it all together:

from blessed import Terminal

term = Terminal()

print(term.bold_underline_green_on_yellow('Woo'))

I’d be remiss if I didn’t credit couleur, where I probably got the idea for all this mashing.

This compound notation comes in handy if you want to allow users to customize formatting, just allow compound formatters, like bold_green, as a command line argument or configuration item such as in the tprint.py demonstration script.

Moving The Cursor

If you just want to move and aren’t worried about returning, do something like this:

from blessed import Terminal

term = Terminal()
print(term.move_xy(10, 1) + 'Hi, mom!')

There are three basic direct movement capabilities:

move_xy(x, y)

Position cursor at given x, y.

move_x(x)

Position cursor at column x.

move_y(y)

Position cursor at row y.

home

Position cursor at (0, 0).

And your basic set of relative capabilities:

move_up or move_up(y)

Position cursor 1 or y cells above the current position.

move_down or move_down(y)

Position cursor 1 or y cells below the current position.

move_left or move_left(x)

Position cursor 1 or x cells left of the current position.

move_right or move_right(x)

Position cursor 1 or x cells right of the current position.

A context manager, location() is provided to move the cursor to an (x, y) screen position and restore the previous position on exit:

from blessed import Terminal

term = Terminal()

with term.location(0, term.height - 1):
    print('Here is the bottom.')

print('This is back where I came from.')

Parameters to location() are the optional x and/or y keyword arguments. When only one argument is used, only the row or column is positioned. When both arguments are omitted, it saves the current cursor position, without performing any movement, but restore that position on exit:

with term.location():
    print(term.move_xy(1, 1) + 'Hi')
    print(term.move_xy(9, 9) + 'Mom')

Note

calls to location() may not be nested.

Finding The Cursor

We can determine the cursor’s current position at anytime using get_location(), returning the current (y, x) location. This uses a kind of “answer back” sequence that your terminal emulator responds to. If the terminal may not respond, the timeout keyword argument can be specified to return coordinates (-1, -1) after a blocking timeout:

from blessed import Terminal

term = Terminal()

row, col = term.get_location(timeout=5)

if row < term.height:
    print(term.move_y(term.height) + 'Get down there!')

One-Notch Movement

Finally, there are some parameterless movement capabilities that move the cursor one character in various directions:

  • move_left

  • move_right

  • move_up

  • move_down

Note

move_down is often valued as \n, which additionally returns the carriage to column 0, depending on your terminal emulator, and may also destructively destroy any characters at the given position to the end of margin.

Height And Width

Use the height and width properties to determine the size of the window:

from blessed import Terminal

term = Terminal()
height, width = term.height, term.width
with term.location(x=term.width / 3, y=term.height / 3):
    print('1/3 ways in!')

These values are always current. To detect when the size of the window changes, you may author a callback for SIGWINCH signals:

import signal
from blessed import Terminal

term = Terminal()

def on_resize(sig, action):
    print('height={t.height}, width={t.width}'.format(t=term))

signal.signal(signal.SIGWINCH, on_resize)

# wait for keypress
term.inkey()

Note

This is not compatible with Windows!

Clearing The Screen

Blessed provides syntactic sugar over some screen-clearing capabilities:

clear

Clear the whole screen.

clear_eol

Clear to the end of the line.

clear_bol

Clear backward to the beginning of the line.

clear_eos

Clear to the end of screen.

Full-Screen Mode

If you’ve ever noticed a program, such as an editor, restores the previous screen (such as your shell prompt) after exiting, you’re seeing the enter_fullscreen and exit_fullscreen attributes in effect.

enter_fullscreen

Switch to alternate screen, previous screen is stored by terminal driver.

exit_fullscreen

Switch back to standard screen, restoring the same terminal state.

There’s also a context manager you can use as a shortcut:

from __future__ import division
from blessed import Terminal

term = Terminal()
with term.fullscreen():
    print(term.move_y(term.height // 2) +
          term.center('press any key').rstrip())
    term.inkey()

Pipe Savvy

If your program isn’t attached to a terminal, such as piped to a program like less(1) or redirected to a file, all the capability attributes on Terminal will return empty strings. You’ll get a nice-looking file without any formatting codes gumming up the works.

If you want to override this, such as when piping output to less -r, pass argument value True to the force_styling parameter.

In any case, there is a does_styling attribute that lets you see whether the terminal attached to the output stream is capable of formatting. If it is False, you may refrain from drawing progress bars and other frippery and just stick to content:

from blessed import Terminal

term = Terminal()
if term.does_styling:
    with term.location(x=0, y=term.height - 1):
        print('Progress: [=======>   ]')
print(term.bold("60%"))

Sequence Awareness

Blessed may measure the printable width of strings containing sequences, providing center(), ljust(), and rjust() methods, using the terminal screen’s width as the default width value:

from __future__ import division
from blessed import Terminal

term = Terminal()
with term.location(y=term.height // 2):
    print(term.center(term.bold('bold and centered')))

Any string containing sequences may have its printable length measured using the length() method.

Additionally, a sequence-aware version of textwrap.wrap() is supplied as class as method wrap() that is also sequence-aware, so now you may word-wrap strings containing sequences. The following example displays a poem word-wrapped to 25 columns:

from blessed import Terminal

term = Terminal()

poem = (term.bold_cyan('Plan difficult tasks'),
        term.cyan('through the simplest tasks'),
        term.bold_cyan('Achieve large tasks'),
        term.cyan('through the smallest tasks'))

for line in poem:
    print('\n'.join(term.wrap(line, width=25, subsequent_indent=' ' * 4)))

Sometimes it is necessary to make sense of sequences, and to distinguish them from plain text. The split_seqs() method can allow us to iterate over a terminal string by its characters or sequences:

from blessed import Terminal

term = Terminal()

phrase = term.bold('bbq')
print(term.split_seqs(phrase))

Will display something like, ['\x1b[1m', 'b', 'b', 'q', '\x1b(B', '\x1b[m']

Similarly, the method strip_seqs() may be used on a string to remove all occurrences of terminal sequences:

from blessed import Terminal

term = Terminal()
phrase = term.bold_black('coffee')
print(repr(term.strip_seqs(phrase)))

Will display only 'coffee'

Keyboard Input

The built-in python function raw_input() does not return a value until the return key is pressed, and is not suitable for detecting each individual keypress, much less arrow or function keys.

Furthermore, when calling os.read() on input stream, only bytes are received, which must be decoded to unicode using the locale-preferred encoding. Finally, multiple bytes may be emitted which must be paired with some verb like KEY_LEFT: blessed handles all of these special cases for you!

cbreak

The context manager cbreak() can be used to enter key-at-a-time mode: Any keypress by the user is immediately consumed by read calls:

from blessed import Terminal
import sys

term = Terminal()

with term.cbreak():
    # block until any single key is pressed.
    sys.stdin.read(1)

The mode entered using cbreak() is called cbreak(3) in curses:

The cbreak routine disables line buffering and erase/kill character-processing (interrupt and flow control characters are unaffected), making characters typed by the user immediately available to the program.

raw

raw() is similar to cbreak, except that control-C and other keystrokes are “ignored”, and received as their keystroke value rather than interrupting the program with signals.

Output processing is also disabled, you must print phrases with carriage return after newline. Without raw mode:

print("hello, world.")

With raw mode:

print("hello, world.", endl="\r\n")

inkey

The method inkey() combined with cbreak completes the circle of providing key-at-a-time keyboard input with multibyte encoding and awareness of application keys.

inkey() resolves many issues with terminal input by returning a unicode-derived Keystroke instance. Its return value may be printed, joined with, or compared like any other unicode strings, it also provides the special attributes is_sequence, code, and name:

from blessed import Terminal

term = Terminal()

print("press 'q' to quit.")
with term.cbreak():
    val = ''
    while val.lower() != 'q':
        val = term.inkey(timeout=5)
        if not val:
           # timeout
           print("It sure is quiet in here ...")
        elif val.is_sequence:
           print("got sequence: {0}.".format((str(val), val.name, val.code)))
        elif val:
           print("got {0}.".format(val))
    print('bye!')

Its output might appear as:

got sequence: ('\x1b[A', 'KEY_UP', 259).
got sequence: ('\x1b[1;2A', 'KEY_SUP', 337).
got sequence: ('\x1b[17~', 'KEY_F6', 270).
got sequence: ('\x1b', 'KEY_ESCAPE', 361).
got sequence: ('\n', 'KEY_ENTER', 343).
got /.
It sure is quiet in here ...
got sequence: ('\x1bOP', 'KEY_F1', 265).
It sure is quiet in here ...
got q.
bye!

A timeout value of None (default) will block forever until a keypress is received. Any other value specifies the length of time to poll for input: if no input is received after the given time has elapsed, an empty string is returned. A timeout value of 0 is non-blocking.

keyboard codes

When the is_sequence property tests True, the value is a special application key of the keyboard. The code attribute may then be compared with attributes of Terminal, which are duplicated from those found in curs_getch(3), or those constants in curses beginning with phrase KEY_.

Some of these mnemonics are shorthand or predate modern PC terms and are difficult to recall. The following helpful aliases are provided instead:

blessed

curses

note

KEY_DELETE

KEY_DC

chr(127).

KEY_TAB

chr(9)

KEY_INSERT

KEY_IC

KEY_PGUP

KEY_PPAGE

KEY_PGDOWN

KEY_NPAGE

KEY_ESCAPE

KEY_EXIT

KEY_SUP

KEY_SR

(shift + up)

KEY_SDOWN

KEY_SF

(shift + down)

KEY_DOWN_LEFT

KEY_C1

(keypad lower-left)

KEY_UP_RIGHT

KEY_A1

(keypad upper-left)

KEY_DOWN_RIGHT

KEY_C3

(keypad lower-left)

KEY_UP_RIGHT

KEY_A3

(keypad lower-right)

KEY_CENTER

KEY_B2

(keypad center)

KEY_BEGIN

KEY_BEG

The name property will prefer these aliases over the built-in curses names.

The following are not available in the curses module, but are provided for keypad support, especially where the keypad() context manager is used with numlock on:

  • KEY_KP_MULTIPLY

  • KEY_KP_ADD

  • KEY_KP_SEPARATOR

  • KEY_KP_SUBTRACT

  • KEY_KP_DECIMAL

  • KEY_KP_DIVIDE

  • KEY_KP_0 through KEY_KP_9