This library is in the Adafruit CircuitPython bundle for CircuitPython 10.0.0.alpha.8 and later
Writes to the Terminal with color escape codes may be done with the adafruit_color_terminal.write() library. The library provides, at present, a more complete implementation of the ANSI/VT100 escape sequence handling than terminalio.Terminal. If you are doing extensive work with colors, using the adafruit_color_terminal library is recommended.
Like terminalio.Terminal, output is not via print or Label.labelbut uses the write method. This places text at the bottom of the display, unless there are ANSI/VT100 Escape Codes embedded in the text to move the cursor to a desired location.
Please refer to Read The Docs for more information and Read the Docs example.
Note that the escape sequence used to change colors of text must immediately precede the text being written. As currently implemented, writing the color change escape sequence in one write and then the text in a second write does not result in text of the desired color.
Below is a simple color Terminal program which uses DVI.
# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import supervisor
from adafruit_fruitjam import peripherals
from displayio import Group
from terminalio import FONT
from adafruit_color_terminal import ColorTerminal
main_group = Group()
display = supervisor.runtime.display
if display is None or peripherals.get_display_config()[2] < 4:
print(
"To use ColorTerminal there must be an initialized display with a color depth at least 4."
)
print(
"Initializing display to default size 640x480 with color depth 8, ",
"if you do not want this configuration then initialize the display ",
"before running this example.",
)
peripherals.request_display_config(640, 480, 8)
font_bb = FONT.get_bounding_box()
screen_size = (display.width // font_bb[0], display.height // font_bb[1])
terminal = ColorTerminal(FONT, screen_size[0], screen_size[1])
main_group.append(terminal.tilegrid)
black = chr(27) + "[30m"
red = chr(27) + "[31m"
green = chr(27) + "[32m"
yellow = chr(27) + "[33m"
blue = chr(27) + "[34m"
magenta = chr(27) + "[35m"
cyan = chr(27) + "[36m"
white = chr(27) + "[37m"
reset = chr(27) + "[0m"
message = f"Hello {green}World{reset} {yellow}ANSI\n"
terminal.write(message)
print(message, end="")
message = f"{magenta}Terminal {red}Colors{reset}"
terminal.write(message)
print(message)
display.root_group = main_group
print(terminal.cursor_x, terminal.cursor_y)
move_cursor = chr(27) + "[10;10H"
terminal.write(f" Something {move_cursor}{cyan} Else{reset}")
while True:
pass
ANSI/VT100 Escape Codes are introduced into a text output stream to alter certain behaviors in working with text. Originating in the later 1970s, it became a standard due to use on the popular DEC VT100 terminals on Digital Equipment Corporation and Unix systems. The Unix curses library was written to facilitate escape code use. With graphical displays becoming more common, escape code use tapered off although it is still used worldwide. It's great for use on resource constrained systems (like microcontrollers) and for porting code which uses curses to other systems as the graphics system doesn't need to be reinvented.
Common codes clear the screen, position the cursor to a row and column, and set a specific color to write text out.
Here is an example of using the adafruit_color_terminal library to write multiple colors on a screen with an LVGL font (Code Page 437, the one IBM used in their original PC).
This program demonstrates:
- Using 8 colors which align with the ANSI terminal color codes
- Using a font other than
terminalio.Terminal. This uses an LVGL font that contains many of the characters in the IBM CP437 IBM PC font which includes "drawing characters" - Moving the cursor to positions and writing text of a certain color in that location.
- Drawing in special characters in a font
# SPDX-FileCopyrightText: Copyright (c) 2025 Tim C for Adafruit Industries
# SPDX-FileCopyrightText: Copyright (c) 2025 Anne Barela for Adafruit Industries
#
# SPDX-License-Identifier: MIT
#
# Make an adafruit_color_terminal terminal with ASCI escape character support
# This uses a Code Page 437 LVGL font to draw a box also
#
import gc
import supervisor
import displayio
from lvfontio import OnDiskFont
from adafruit_fruitjam.peripherals import request_display_config
from adafruit_color_terminal import ColorTerminal
# Routine goto - position output to row, column
def goto(row, column):
terminal.write(f"\x1B[{int(row)};{int(column)}H")
# Routine cls - clear screen
def cls():
terminal.write("\x1B[2J")
goto(1, 1)
def draw_box(width, height, x, y, color_box):
top_left = '\xDA'
horizontal = '\xC4'
top_right = '\xBF'
vertical = '\xB3'
bottom_left = '\xC0'
bottom_right = '\xD9'
if width < 3 or height < 3:
return
# Top line
out_char(top_left + horizontal*(width - 2) + top_right, x, y, color_box)
# Middle lines
for i in range(1, height - 1):
out_char(vertical + ' '*(width - 2) + vertical, x+i, y, color_box)
# Bottom line
out_char(bottom_left + horizontal*(width - 2) + bottom_right, x+height-1,
y, color_box)
def out_char(value, row, column, color):
goto(row, column)
terminal.write(f"\033[3{color}m"+value)
def set_color(palette_index):
"""Set FOREGROUND color only"""
if not (0 <= palette_index <= 7): # pylint: disable=superfluous-parens
raise ValueError("Palette index must be between 0 and 7")
terminal.write(f"\033[3{palette_index}m")
def set_bgcolor(palette_index):
"""Set BACKGROUND color only"""
if not (0 <= palette_index <= 7): # pylint: disable=superfluous-parens
raise ValueError("Palette index must be between 0 and 7")
terminal.write(f"\033[4{palette_index}m")
def reset_ansi():
"""Reset to default colors (usually white on black)"""
terminal.write("\033[0m")
def set_colors(fg_color=None, bg_color=None):
"""Set both foreground and background colors"""
if fg_color is not None:
set_color(fg_color)
if bg_color is not None:
set_bgcolor(bg_color)
# Use the easy library call to set the resolution
request_display_config(640, 480)
print(f"\nFree before display init: {gc.mem_free()}")
# Initialize display
main_group = displayio.Group()
display = supervisor.runtime.display
display.root_group = main_group
print(f"free: {gc.mem_free()}")
colors = 8
red = 0xff0000
yellow = 0xcccc00
orange = 0xff5500
blue = 0x0000ff
pink = 0xff00ff
purple = 0x5500ff
white = 0xffffff
green = 0x00ff00
aqua = 0x125690
black = 0x000000
terminal_palette = displayio.Palette(colors)
terminal_palette[0] = black
terminal_palette[1] = red
terminal_palette[2] = green
terminal_palette[3] = yellow
terminal_palette[4] = blue
terminal_palette[5] = purple
terminal_palette[6] = aqua
terminal_palette[7] = white
font = OnDiskFont("fonts/cp437_16h.bin") # LVGL .bin font
char_size = font.get_bounding_box()
print(f"Character size: {char_size}")
print(f"font.bitmap info: {font.bitmap.width}, {font.bitmap.height}")
screen_size = (display.width // char_size[0], display.height // char_size[1])
print(f"Screen size: {screen_size}")
print(f"Screen depth: {display.framebuffer.color_depth} bits")
terminal = ColorTerminal(font, screen_size[0], screen_size[1])
main_group.append(terminal.tilegrid)
print("Created Color Terminal")
# Clear screen and set initial colors properly
cls()
# Test individual colored text - each should stay its own color
out_char("Red (1,1)", 1, 1, 1) # Red text, then reset
out_char("Green (10,1)", 10, 1, 2) # Green text, then reset
out_char("Blue (1,30)", 1, 30, 4) # Blue text, then reset
out_char("Yellow (10,30)", 10, 30, 3) # Yellow text, then reset
out_char("Magenta (15,1)", 15, 1, 5) # Magenta text, then reset
out_char("Cyan (15,30)", 15, 30, 6) # Cyan text, then reset
# Draw box in a specific color (should be yellow)
draw_box(10, 8, 6, 17, 3)
# Write some normal text (should be in default color)
goto(20, 5)
terminal.write("This should be default color")
# Write more colored text using out_char
out_char("Isolated Red", 22, 5, 1)
out_char("Isolated Green", 23, 5, 2)
out_char("Isolated Blue", 24, 5, 4)
# Final text should be in default color
goto(26, 5)
terminal.write("This should also be default color")
print("Done - all colors should be visible simultaneously")
while True:
pass
Page last edited July 16, 2025
Text editor powered by tinymce.