Failing Productively

Get Rich or Die TTYing – Part 2: Console markup

This is the second instalment in a series exploring everything you can (and perhaps sometimes shouldn’t) do with Rich – a Python library for styling terminal output. Oh, and everyone’s favourite mid-2000s rapper is along for the ride. My last post covered the blinging up the REPL.

Today’s topic is Rich’s console markup.

So, taking inspiration from the words of Fiddy himself:

It ain’t my fault, I just reach for style
I’m hot, I breaks it down
It ain’t my fault, you can’t break it down
The way I break it down

— 50 Cent, God Gave Me Style

Overview

Rich uses a simple markup language for quickly annotating input passed to print(), log(), or anywhere else Rich accepts strings, e.g.:

from rich import print

print("[bold]G-Unit[/bold]")

The first set of square brackets contains the style (or styles) to be applied to all text until the closing set ([/bold] in this case).

Styled text can also be closed without specifying the style again, i.e. just with [/]. Further, you can omit the closing syntax entirely if you’d like the style to be applied until the end of the line. Therefore all of the following print statements produce the same output.

print("[underline]Get Rich or Die Tryin'[/underline]")
print("[underline]Get Rich or Die Tryin'[/]")
print("[underline]Get Rich or Die Tryin'")
# there's even a short name for this style
print("[u]Get Rich or Die Tryin'")

Get Rich or Die Tryin’, underlined

“Don’t care, didn’t ask,” I hear your atrophied attention span say.

I get it. We’d all rather be in da club, bottle full of bub’. But when you consider the alternative to the previous example relies on wrapping your string in ANSI escape sequences, i.e.

print("\x1b[4mGet Rich Die Tryin'\x1b[24m")

I think we can all agree Rich is a real timesaver for the modern hustler.

As an aside, I was interested to see that the markup language is loosely based on BBCode (“Bulletin Board Code”), since a similar markup language is also used by Spectre.Console, a dotnet package with close functionality to Rich.

Colour

Colour can be added to text in one of two ways:

  1. Specifying one of the 256 named colours, either by name (magenta), or number (color(5))
  2. Supplying a hex value, e.g. #bb2a25.

So,

print("[magenta]Go, shawty, it's your birthday[/]")
print("[color(6)]We gon' party like it's your birthday[/]")
print("[#e28cf8]We gon' sip Bacardí like it's your birthday[/]")

Produces:

3 lines of ‘In da Club’, each a different colour

It’s worth noting that the first 16 named colours, e.g. color(1)/red, are generally defined by a terminal’s colour scheme, rather than being an exact colour like #d70000. This is a good thing. With terminal-defined colours, although you lose precise control of the output, you know they’ll fit with the user’s theme and have reasonable contrast.

Styled text

Beyond colour, Rich can add styles like bold, underline and italics to your text. To illustrate, I’ve styled some heartfelt lines from 21 Questions.

Style Result
[bold]/[b] Monospace text printed in bold
[italic]/[i] Monospace text printed in italic
[dim]/[d] Monospace text printed dimly
[underline]/[u] Monospace text printed with underline
[underline2]/[uu] Monospace text printed with two underlines
[strike]/[s] Monospace text printed with strikethrough
[reverse]/[r] Monospace text printed in inverted colours

The table above contains common styles supported by many – but not all – modern terminals like Ghostty, Kitty, WezTerm, Konsole and the like. On the left is the style (and abbreviated form); on the right is its corresponding output.

Weird stuff your terminal probably won’t support

Rich also allows for styles which are very seldom supported by modern terminals. I haven’t included images of output in this section, since all except [overline] are difficult to display.

Combining styles

Styles can be combined and nested within each other. To demonstrate,

print("[underline green on white]God give me style, God give me grace[/]")
print("[italic magenta]God put a [yellow]smile[/] on my face[/]")

Becomes:

God give me style, God give me grace, God put a smile on my face

Remember: blue, white and magenta are part of the 16 colours defined by your terminal’s theme (here, Rosé Pine Moon), so the snippet above will probably look different if you run it yourself.

Emoji

Emoji can be referred to via their name surrounded by colons:

print(":heavy_dollar_sign: :heavy_division_sign: :two:")

# is the equivalent of
print("💲 ➗ 2⃣")

For a complete list of available emoji names + examples, run python -m rich.emoji in your terminal.

Lastly, you can add interactive links to your output too.

url = "https://web.archive.org/web/20060116005724/http://www.50cent.com/"
print(f"Here's 50's [link={url}]website back in 2006.[/]")

Here’s 50’s website back in 2006, with last four words underlined

The caveat here is, again, as long as your terminal supports them.

There’s no real standard around how they’ll be displayed either. Some terminals will underline them. Some won’t. Others will only underline them on hover. Typically, you will need to Ctrl+Click to follow them too.

Conclusion

That’s a (w)rap! I encourage you to start adding some console markup to your scripts, new or existing. With minimal effort, you can add some swag to your print() and log() statements and generally make the terminal a more interesting place. Just don’t overdo it (or do!), and keep in mind that not all terminals are created equal.

#Python #Rich #Grodt