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¶
The basic 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.
The less commonly supported capabilities:
dim
- Enable half-bright mode.
underline
- Enable underline mode.
no_underline
- Exit underline mode.
italic
- Enable italicized text.
no_italic
- Exit italics.
shadow
- Enable shadow text mode (rare).
no_shadow
- Exit shadow text mode.
standout
- Enable standout mode (often, an alias for
reverse
). no_standout
- Exit standout mode.
subscript
- Enable subscript mode.
no_subscript
- Exit subscript mode.
superscript
- Enable superscript mode.
no_superscript
- Exit superscript mode.
flash
- Visual bell, flashes the screen.
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, or a non-tty
is used as an output stream, an empty string is returned.
Colors¶
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 gray!
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¶
When you want to move the cursor, you have a few choices:
location(x=None, y=None)
context manager.move(row, col)
capability.move_y(row)
capability.move_x(col)
capability.
Warning
The location()
method receives arguments in
positional order (x, y), whereas the move()
capability receives
arguments in order (y, x). Please use keyword arguments as a later
release may correct the argument order of location()
.
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!')
Moving Temporarily¶
A context manager, location()
is provided to move the cursor
to an (x, y) screen position and restore the previous position upon 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:
with term.location(y=10):
print('We changed just the row.')
When omitted, it saves the cursor position and restore it upon exit:
with term.location():
print(term.move(1, 1) + 'Hi')
print(term.move(9, 9) + 'Mom')
Note
calls to location()
may not be nested.
Moving Permanently¶
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(10, 1) + 'Hi, mom!')
move(y, x)
- Position cursor at given y, x.
move_x(x)
- Position cursor at column x.
move_y(y)
- Position cursor at row y.
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()
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
throughKEY_KP_9