Python - ncurses printing html as colors
Jump to navigation
Jump to search
Contents
About
ncurses is text-based user interface library. Here we build on examples and provide functions capable of taking a html string, and using it to change font color and style as it prints.
The goal.... instead of needing to break apart formatted text like this:
screen.addstr(1, 0, 'Hello ', curses.A_NORMAL | curses.color_pair(1))
screen.addstr(1, 6, 'bold', curses.A_BOLD | curses.color_pair(1))
screen.addstr(1, 10, ' world', curses.A_NORMAL | curses.color_pair(1))
screen.addstr(2, 0, 'See: ', curses.A_NORMAL | curses.color_pair(1))
screen.addstr(2, 5, 'www.gnu.org', curses.A_UNDERLINED | curses.color_pair(8))
We want this:
print_html_str(1, 0, 'Hello <b>bold</b> world<br>See: <a>www.gnu.org</a>', True)
ncurses_color_sub.py
ncurses_color_sub.py
#!/usr/bin/env python
# ncurses_color_sub.py - ncurses interface which inputs a HTML like
# string and outputs with color.
# See: http://andrewnoske.com/wiki/Python_-_ncurses_printing_html_as_colors
#
# Usage:
# ncurses_color_sub.py
#
# Usage examples:
# $ python ncurses_color_sub.py
import curses
demo_str = """<h1>Heading</h1>
Bold text: <b>bold is yellow</b>.
Blue hyperlink: <a>http://andrewnoske.com/wiki/</a>.
"""
def get_style_for_html_tag(tag_inner_str):
"""Inputs html tag label and returns matching font color/style for ncurses.
Args:
tag_inner_str: inner contents of a HTML tag, such as 'b' for a start bold tag.
Not many tag types are supported and any unrecognized tags or closing
tags (eg: '/b') return a default style - in this case normal white text.
Returns:
A curses font specification suitable for input into 'screen.addstr()'.
"""
style_default = curses.A_NORMAL | curses.color_pair(7) # White.
style_b = curses.A_NORMAL | curses.color_pair(3) # Yellow.
style_h1 = curses.A_BOLD | curses.color_pair(6) # Cyan bold.
style_a = curses.A_UNDERLINE | curses.color_pair(4) # Blue underlined.
if tag_inner_str == 'b':
return style_b
elif tag_inner_str == 'h1':
return style_h1
elif tag_inner_str == 'a' or tag_inner_str.startswith('a '):
return style_a
else:
return style_default
def print_html_str(y_start, x_start, html_str,
in_screen, make_newlines_br):
"""Prints to ncurses html where certain tags change the font color/style.
Args:
y_start: col position to start at.
x_start: row position to start at.
html_str: a html text string such as 'this <b>example</b>'.
in_screen: an ncurses screen generated with 'curses.initscr()'
make_newlines_br: if true will turn any newlines into '<br>' before
processing otherwise newlines are simply ignored and only '<br>'
or '<p>' will go to the next line.
Returns:
The number of lines (rows) output, which will be at least one, but more
if there are '<br>' and/or '<p>' tags.
"""
curr_color = get_style_for_html_tag('default')
x = x_start
y = y_start
remaining_str = html_str.replace('\n', '')
if make_newlines_br:
remaining_str = html_str.replace('\n', '<br>')
while len(remaining_str) > 0:
pos = remaining_str.find('<') # Find start of tag (<).
if pos >= 0:
# Output part up to start of tag:
part_str = remaining_str[:pos]
in_screen.addstr(y, x, part_str, curr_color)
remaining_str = remaining_str[pos+1:]
x = x + pos
# Determine what tag is:
pos_end = remaining_str.find('>') # Find end of tag (<).
if pos_end >= 0:
tag_str = remaining_str[:pos_end]
curr_color = get_style_for_html_tag(tag_str)
remaining_str = remaining_str[pos_end+1:]
if tag_str == 'br' or tag_str == 'p':
y = y+1
x = x_start
else:
# Output everything remaining:
in_screen.addstr(y, x, remaining_str, curr_color)
remaining_str = ''
return y - y_start + 1
def create_color_pairs():
"""Creates a set of indexed color pairs for curses for each text color.
Notice these are ordered 1-8 in rough order of 'ANSI color' values
but with black as 8 instead of 0, since numbers start at 1.
See: http://andrewnoske.com/wiki/Unix_-_ANSI_colors
"""
curses.start_color()
curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK)
curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK)
curses.init_pair(3, curses.COLOR_YELLOW, curses.COLOR_BLACK)
curses.init_pair(4, curses.COLOR_BLUE, curses.COLOR_BLACK)
curses.init_pair(5, curses.COLOR_MAGENTA, curses.COLOR_BLACK)
curses.init_pair(6, curses.COLOR_CYAN, curses.COLOR_BLACK)
curses.init_pair(7, curses.COLOR_WHITE, curses.COLOR_BLACK)
curses.init_pair(8, curses.COLOR_BLACK, curses.COLOR_BLACK)
def main():
screen = curses.initscr()
create_color_pairs()
screen.clear()
screen.border(0)
print_html_str(2, 5, 'Here is a <b>basic test</b>', screen, False)
print_html_str(5, 5, demo_str, screen, True)
screen.refresh()
opt = screen.getch() # Wait for user to enter character.
curses.endwin()
if __name__ == '__main__':
main()
See Also
- Unix_-_ncurses_ui - simpler ncurses examples written in Python.
Links
- Ncurses Official Site on gnu.org - Official site
- Curses API Documentation