Colors and Styles

say has built-in support for style-driven formatting. By default, ANSI terminal colors and styles are automagically supported.

answer = 42

say("The answer is {answer:style=bold+red}")

This uses the ansicolors module, though with a slightly more permissive syntax. Available colors are ‘black’, ‘blue’, ‘cyan’, ‘green’, ‘magenta’, ‘red’, ‘white’, and ‘yellow’. Available styles are ‘bold’, ‘italic’, ‘underline’, ‘blink’, ‘blink2’, ‘faint’, ‘negative’, ‘concealed’, and ‘crossed’. These styles can be combined with a + or | character. Note, however, that not all styles are available on every terminal.

Note

When naming a style within the template braces ({}) of format strings, you can quote the style name or not. fmt("{x:style=red+bold}") is equivalent to fmt("{x:style='red+bold'}").

You can define your own styles:

say.style(warning=lambda x: color(x, fg='red'))

Because styles are defined through executables (lambdas, usually), they can include decisions or text transformations of arbitrary complexity. For example:

say.style(redwarn=lambda n: color(n, fg='red', style='bold') if int(n) < 0 else n)
...
say("Result: {n:style=redwarn}")

That will display the number n in bold red characters, but only if it’s value is negative. For positive numbers, n is displayed normally.

Or define a style where a message is surrounded by red stars:

say.style(stars=lambda x: fmt('*** ', style='red') + \
                          fmt(x,      style='black') + \
                          fmt(' ***', style='red'))
say.style(redacted=lambda x: 'x' * len(x))

message = 'hey'
say(message, style='stars')
say(message, style='redacted')

Yields:

*** hey ***
xxx

(with red stars)

Note

Style defining lambdas (or functions) take string arguments. If the string is logically a number, it must be then cast into an int, float, or whatever. The code must ultimate return a string.

You can also apply a style to the entire contents of a say or fmt invocation:

say("There is green everywhere!", style='green|underline')

Or try:

say.set(prefix=numberer(template=color('{n:>3}: ', fg='green')), \
        wrap=20)
say('a long paragraph with gobs of text', style='indigo')

This correctly puts the line numbers in green, wraps the lines to 20 characters, and puts the text in indigo.

Styled formatting is an extremely powerful approach, giving the same kind of flexibility and abstraction seen for styles in word processors and CSS-based Web design. It will be further developed. Plans already include replacing textwrap with an ANSI-savvy text wrapping module, providing simpler ways to state complex formatting, and mechanisms to auto-map styles into HTML output.