Terminal rendering library with full character-level control. Rich on steroids.
Project description
libtodraw
Terminal rendering library with full character-level control.
Pure Python. Zero dependencies. Install with pip install libtodraw.
Author: silence — t.me/hatedfame
pip install libtodraw
from libtodraw import Console
c = Console()
c.print("[bold green]Hello![/bold green] [red]World[/red]")
Table of Contents
- Quick Start
- Console
- Markup
- Canvas — Character Control
- Colors
- Styles
- Text
- Table
- Panel
- Tree
- Syntax Highlighting
- Markdown
- Layout & Columns
- Progress Bars
- Spinners & Status
- Live Display
- Rules / Separators
- Export
- Inspector & Debug
- Terminal Detection
- API Reference
Quick Start
from libtodraw import Console, Table, Panel, Tree, Syntax, Markdown
c = Console()
# Styled text
c.print("[bold red]Error:[/bold red] file not found")
# Table
t = Table()
t.add_column("Name", style="cyan")
t.add_column("Score", style="green")
t.add_row("Alice", "95")
c.print(t)
# Panel
c.print(Panel("[yellow]Important message[/yellow]", title="Alert"))
# Syntax highlighting
c.print(Syntax("print('hello')", "python", theme="monokai"))
# Markdown
c.print(Markdown("# Title\n\n- item 1\n- item 2"))
Console
Console is the core object. It handles printing, markup, styles, and output.
from libtodraw import Console
c = Console()
# Basic print
c.print("Hello")
# With markup
c.print("[bold green]Success![/bold green]")
# With style
c.print("Error", style="bold red")
# Separator
c.rule("Section")
# Logging (with caller info)
c.log("something happened")
# Input
name = c.input("[cyan]Name:[/cyan] ")
# Clear screen
c.clear()
Console Options
c = Console(
file=sys.stdout, # Output file (default: stderr)
width=80, # Fixed width
height=24, # Fixed height
color_system="truecolor", # "truecolor", "256", "16", "8", "no-color"
force_terminal=True, # Force terminal mode
highlight=True, # Auto-highlight code
markup=True, # Enable [tag] markup
)
Markup
Rich-style markup: [style]text[/style].
Colors
c.print("[red]Red text[/red]")
c.print("[#ff6600]Orange hex color[/]")
c.print("[green]Green[/green] [blue]Blue[/blue]")
Styles
c.print("[bold]Bold[/bold]")
c.print("[italic]Italic[/italic]")
c.print("[underline]Underline[/underline]")
c.print("[strike]Strikethrough[/strike]")
c.print("[dim]Dimmed[/dim]")
c.print("[blink]Blinking (terminal dependent)[/blink]")
c.print("[reverse]Inverted[/reverse]")
Combining
c.print("[bold red on blue]Bold red on blue background[/]")
c.print("[bold italic green]Bold italic green[/]")
Background
c.print("[bg=#ff0000]White on red background[/]")
c.print("[bg=blue]Text on blue[/]")
Gradient
c.print("[gradient=red,blue]Rainbow gradient text[/gradient]")
c.print("[gradient=#00ff00,#ff00ff]Custom hex gradient[/gradient]")
Gradient Engine (v1.0.2)
Full control over gradients: angle, multi-color, percentage, direction presets.
from libtodraw import Gradient, Canvas, Color
# Basic 2-color gradient
g = Gradient("red", "blue")
# Multi-color gradient
g = Gradient("red", "yellow", "green", "blue")
# With direction preset
g = Gradient("red", "blue", angle="top-left")
g = Gradient("red", "blue", angle="bottom-right")
g = Gradient("red", "blue", angle="center") # radial
# Custom angle (degrees)
g = Gradient("red", "blue", angle=45)
g = Gradient("red", "blue", angle=90)
g = Gradient("red", "blue", angle=135)
# Percentage control
g = Gradient("red", "blue", color1_pct=0.2, color2_pct=0.8)
# Available directions:
# left, right, top, bottom
# top-left, top-right, bottom-left, bottom-right
# center (radial), diagonal, reverse-diagonal
# Apply to canvas
canvas = Canvas(80, 24)
canvas.apply_gradient(0, 0, 80, 24, g)
canvas.gradient_fill(0, 0, 80, 5, Color(255,0,0), Color(0,0,255), angle="diagonal")
canvas.gradient_border(0, 0, 80, 10, Color(255,200,0), Color(0,100,255), angle="center")
Links
c.print("[link=https://example.com]Click here[/link]")
Escaping
c.print("\[not a tag\]") # Literal brackets
Canvas — Character Control
Full control over every single cell. This is what makes libtodraw different.
from libtodraw import Canvas, Style, Color
c = Canvas(80, 24) # width, height
# Set single character
c.set(5, 3, "X", Style(color=Color(255, 0, 0)))
# Place text
c.put(10, 5, "Hello World", Style(bold=True))
# Fill region
c.fill(0, 0, 80, 24, " ", Style(bgcolor=Color(30, 30, 50)))
# Draw shapes
c.draw_box(5, 5, 30, 10, box_type="rounded")
c.draw_circle(40, 12, 5, "●", Style(color=Color(255, 100, 100)))
c.draw_line(10, 10, 70, 20, "·", Style(color=Color(100, 255, 100)))
# Gradient fill
c.gradient_fill(0, 0, 80, 1, Color(255, 0, 0), Color(0, 0, 255))
# Gradient border
c.gradient_border(10, 5, 40, 15, Color(255, 100, 0), Color(0, 100, 255))
# Render to terminal
c.print()
Canvas API
Single Cell Control
c.set(x, y, char, style) # Set cell
c.get(x, y) # Get cell → Cell(char, style)
c.set_char(x, y, char) # Set char only
c.set_style(x, y, style) # Set style only
c.clear_cell(x, y) # Reset to blank
c[x, y] # Get cell (bracket syntax)
c[x, y] = ("X", style) # Set cell (bracket syntax)
Regions
c.fill(x, y, w, h, char, style) # Fill rectangle
c.clear(x, y, w, h) # Clear region
c.clear_all() # Clear entire canvas
Drawing Primitives
c.draw_box(x, y, w, h, style=..., box_type="simple")
# box_type: "simple", "rounded", "heavy", "double", "dashed", "dotted"
c.draw_rect(x, y, w, h, border=style, fill=style, chars={...})
c.draw_hline(x, y, length, char="─", style=...)
c.draw_vline(x, y, length, char="│", style=...)
c.draw_circle(cx, cy, radius, char="●", style=..., filled=True)
c.draw_line(x0, y0, x1, y1, char="·", style=...)
Custom border characters:
c.draw_rect(5, 5, 20, 10, chars={
"tl": "╔", "tr": "╗", "bl": "╚", "br": "╝",
"hor": "═", "ver": "║", "fill": " "
})
Text Placement
c.put(x, y, "text", style=...) # Place text
c.put_centered(y, "text", style=...) # Center horizontally
c.put_right(y, "text", style=...) # Right-align
c.put_at(x, y, "text", style=..., align="center", max_width=40)
c.write_line(y, x, "text", justify="left", width=80)
# justify: "left", "center", "right", "full"
Gradients
c.gradient_fill(x, y, w, h, c1, c2, char="█", horizontal=True, angle=None)
c.gradient_border(x, y, w, h, c1, c2, box_type="simple", angle=None)
c.apply_gradient(x, y, w, h, gradient_object, char="█")
Compositing
c.overlay(other_canvas, x=0, y=0, overwrite=True)
c.copy() # Deep copy
c.resize(width, height) # Resize (preserves content)
Inspection
c.get_row(y) # All cells in row → [Cell]
c.get_col(x) # All cells in column → [Cell]
c.get_region(x, y, w, h) # Rectangular region → [[Cell]]
c.find(char) # Find all positions → [(x,y)]
c.to_text() # Plain text (no ANSI)
c.width # Canvas width
c.height # Canvas height
Sub-Regions
region = c.region(x, y, w, h)
region.set(0, 0, "X", style) # Coordinates relative to region
region.put(1, 1, "Hello")
region.fill(char, style)
region.clear()
region.draw_box(style, box_type="heavy")
Colors
Named Colors
from libtodraw import Color
c = Color(255, 0, 0) # RGB
c = Color.from_hex("#ff6600") # Hex
c = Color.from_name("red") # Named
Available names: black, red, green, blue, yellow, cyan, magenta, white, gray, grey, orange, pink, purple, brown, coral, crimson, gold, indigo, lime, maroon, navy, olive, salmon, teal, tomato, turquoise, violet, beige, tan, dark_red, dark_green, dark_blue, dark_yellow, dark_cyan, dark_magenta, dark_gray, light_red, light_green, light_blue, light_yellow, light_cyan, light_magenta, light_gray, steel_blue, sienna, plum, ivory, khaki, lavender, wheat, firebrick.
Color Operations
# Interpolation
blended = color1.lerp(color2, 0.5) # 50% blend
# ANSI output
color.to_ansi_fg() # "\033[38;2;r;g;b;m"
color.to_ansi_bg() # "\033[48;2;r;g;b;m"
# Parse any format
Color.parse("red")
Color.parse("#ff6600")
Color.parse(color_obj) # passthrough
Styles
from libtodraw import Style
s = Style(
color="red",
bgcolor="blue",
bold=True,
dim=False,
italic=True,
underline=False,
blink=False,
reverse=False,
strikethrough=False,
link="https://example.com",
)
# Parse from string
s = Style.parse("bold italic red on blue")
# Merge styles
combined = style1 + style2 # style2 overrides style1
# Generate ANSI
s.to_ansi() # Full escape sequence
s.render("text") # "\033[...mtext\033[0m"
Text
Text is a styled text object with spans.
from libtodraw import Text, Style
t = Text()
t.append("Hello ", Style(bold=True))
t.append("World", Style(color="red"))
# Or chain
t = Text().append("A", Style(bold=True)).append("B")
# Operations
len(t) # Length
t.plain # Plain text
t + other # Concatenate
t[2:5] # Slice
t.truncate(10) # Truncate with ellipsis
t.center(40) # Center in width
t.left(40) # Left-align
t.right(40) # Right-align
t.wrap(40) # Word wrap → [Text]
t.highlight(r"\berror\b", Style(color="red")) # Regex highlight
Table
from libtodraw import Table
t = Table(
show_header=True,
show_lines=True,
expand=False,
border_style="cyan",
header_style="bold white on blue",
padding=(0, 1),
)
t.add_column("Name", style="cyan", no_wrap=True)
t.add_column("Score", style="green")
t.add_column("Status")
t.add_row("Alice", "95", "[green]Active[/green]")
t.add_row("Bob", "87", "[red]Inactive[/red]")
c.print(t)
Panel
from libtodraw import Panel
# Simple panel
c.print(Panel("Hello World"))
# With title and style
c.print(Panel(
"[bold yellow]Important![/bold yellow]",
title="Warning",
subtitle="v1.0",
border_style="red",
box="rounded", # simple, rounded, heavy, double
padding=(1, 2),
expand=True,
width=60,
))
# Panel with content
c.print(Panel(
"Line 1\nLine 2\nLine 3",
title="Log",
border_style="green",
))
Tree
from libtodraw import Tree, TreeNode
root = TreeNode("[bold]project/[/bold]")
src = TreeNode("[cyan]src/[/cyan]")
src.add(TreeNode("main.py"))
src.add(TreeNode("utils.py"))
root.add(src)
root.add(TreeNode("[yellow]Makefile[/yellow]"))
root.add(TreeNode("[dim]README.md[/dim]"))
c.print(Tree(root))
Syntax Highlighting
from libtodraw import Syntax
code = '''
def hello():
print("Hello, World!")
return 42
'''
c.print(Syntax(
code,
lexer="python", # python, javascript, bash, json, rust, go, c, cpp, java, html, css, sql
theme="monokai", # monokai, dracula, solarized, github-dark, one-dark
line_numbers=True,
highlight_lines=[2], # Highlight specific lines
tab_size=4,
start_line=1,
))
Markdown
from libtodraw import Markdown
md = """
# Title
## Subtitle
**Bold** and *italic* text.
- Item 1
- Item 2
```python
x = 1
Blockquote """
c.print(Markdown(md))
---
## Layout & Columns
### Columns
```python
from libtodraw import Columns, Panel
left = Panel("[green]Left[/green]", title="A")
center = Panel("[blue]Center[/blue]", title="B")
right = Panel("[red]Right[/red]", title="C")
c.print(Columns([left, center, right], padding=(0, 1)))
Layout
from libtodraw import Layout
layout = Layout()
layout.split_column(
Layout(name="header", size=3),
Layout(name="body"),
Layout(name="footer", size=3),
)
Progress Bars
from libtodraw import Progress
with Progress() as progress:
task = progress.add_task("Downloading...", total=100)
for i in range(100):
time.sleep(0.01)
progress.update(task, advance=1)
Custom Columns
from libtodraw import Progress, SpinnerColumn, TextColumn, BarColumn, TimeRemainingColumn
with Progress(
SpinnerColumn(),
TextColumn("[bold blue]{task.description}"),
BarColumn(),
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
TimeRemainingColumn(),
) as progress:
task = progress.add_task("Processing...", total=100)
for i in range(100):
time.sleep(0.02)
progress.update(task, advance=1)
Spinners & Status
Spinner
from libtodraw import Spinner
s = Spinner("dots", "Loading...", style="green")
s.start()
time.sleep(2)
s.stop("Done!")
Available spinners: ascii, dots, dots2, line, bar, arc, bounce, arrow, aesthetic, toggle, earth, weather, bouncingBar, christmas.
Status (context manager)
with c.status("Working...", spinner="dots", spinner_style="green"):
time.sleep(2)
Live Display
Real-time updating display.
from libtodraw import Live, Table
with Live(Table()) as live:
for i in range(100):
time.sleep(0.1)
table = Table()
table.add_row(f"Item {i}")
live.update(table)
Rules / Separators
c.rule() # ─────────────────────
c.rule("Section") # ──── Section ────────
c.rule("[bold]Title[/bold]") # Styled title
c.rule(characters="═") # ═══════════════════════
c.rule(characters="─", style="blue") # Colored rule
Export
Text (plain, no ANSI)
from libtodraw import export_text
text = export_text([table, panel, tree])
HTML
from libtodraw import export_html
html = export_html([table, panel])
# Returns HTML with inline CSS styles
Console HTML Export
c.begin_capture()
c.print("[red]Hello[/red]")
c.end_capture()
html = c.get_export()
Inspector & Debug
Object Inspector
from libtodraw import pretty_inspect
pretty_inspect(my_object)
# Shows: type, docstring, methods, properties, attributes
Pretty Traceback
from libtodraw import install_traceback
install_traceback() # Beautiful error output with syntax highlighting
Terminal Detection
from libtodraw import get_size, detect_truecolor, detect_unicode
width, height = get_size() # Terminal dimensions
truecolor = detect_truecolor() # TrueColor support
unicode = detect_unicode() # Unicode support
API Reference
Console
| Method | Description |
|---|---|
print(*objects, end, style, ...) |
Print with markup |
log(*objects) |
Log with caller info |
input(prompt) |
Styled input |
out(*objects) |
Low-level output |
rule(title, style, characters) |
Print separator |
status(text, spinner) |
Status spinner context manager |
capture() |
Capture output context manager |
clear() |
Clear screen |
size() |
Terminal size (w, h) |
options(width, max_width, ...) |
Get console options |
get_style(name) |
Get named style from theme |
push_style(style) / pop_style() |
Style stack |
render(renderable, options) |
Render to lines |
measure(renderable, max_width) |
Measure width |
export_html() |
Export as HTML |
begin_capture() / end_capture() |
Capture for export |
Canvas
| Method | Description |
|---|---|
set(x, y, char, style) |
Set cell |
get(x, y) |
Get cell |
set_char(x, y, char) |
Set char only |
set_style(x, y, style) |
Set style only |
clear_cell(x, y) |
Reset cell |
fill(x, y, w, h, char, style) |
Fill region |
clear(x, y, w, h) |
Clear region |
clear_all() |
Clear canvas |
draw_box(x, y, w, h, style, box_type) |
Draw box |
draw_rect(x, y, w, h, border, fill, chars) |
Draw rectangle |
draw_hline(x, y, len, char, style) |
Horizontal line |
draw_vline(x, y, len, char, style) |
Vertical line |
draw_circle(cx, cy, r, char, style, filled) |
Circle |
draw_line(x0, y0, x1, y1, char, style) |
Line |
put(x, y, text, style) |
Place text |
put_centered(y, text, style) |
Center text |
put_right(y, text, style) |
Right-align text |
put_at(x, y, text, style, align, max_width) |
Text with alignment |
write_line(y, x, text, justify, width) |
Full-line output |
gradient_fill(x, y, w, h, c1, c2, char, horizontal, angle) |
Gradient fill with optional angle |
gradient_border(x, y, w, h, c1, c2, box_type, angle) |
Gradient border with optional angle |
apply_gradient(x, y, w, h, gradient, char) |
Apply Gradient object |
overlay(other, x, y, overwrite) |
Composite canvas |
copy() |
Deep copy |
resize(w, h) |
Resize |
region(x, y, w, h) |
Sub-region |
get_row(y) / get_col(x) |
Row/column access |
get_region(x, y, w, h) |
Region access |
find(char) |
Find character positions |
to_text() |
Plain text export |
render() |
ANSI string |
print(file) |
Print to terminal |
Color
| Method | Description |
|---|---|
Color(r, g, b) |
RGB constructor |
Color.from_hex("#rrggbb") |
From hex string |
Color.from_name("red") |
From named color |
Color.parse(value) |
Parse any format |
color.lerp(other, t) |
Interpolate |
color.to_ansi_fg() |
Foreground ANSI |
color.to_ansi_bg() |
Background ANSI |
Style
| Method | Description |
|---|---|
Style(color, bgcolor, bold, ...) |
Constructor |
Style.parse("bold red on blue") |
Parse string |
style1 + style2 |
Merge styles |
style.to_ansi() |
Generate ANSI |
style.render(text) |
Wrap text with ANSI |
Text
| Method | Description |
|---|---|
Text(text, style) |
Constructor |
text.append(text, style) |
Append span |
text.stylize(style, start, end) |
Apply style to range |
text.plain |
Plain text property |
text.truncate(max_width) |
Truncate |
text.center(width) / left / right |
Align |
text.wrap(width) |
Word wrap |
text.highlight(pattern, style) |
Regex highlight |
Table
| Method | Description |
|---|---|
Table(**kwargs) |
Constructor |
table.add_column(header, **kwargs) |
Add column |
table.add_row(*cells) |
Add row |
Panel
| Method | Description |
|---|---|
Panel(renderable, title, ...) |
Constructor |
Tree
| Method | Description |
|---|---|
Tree(root) |
Constructor |
TreeNode(label) |
Create node |
node.add(child) |
Add child |
Syntax
| Method | Description |
|---|---|
Syntax(code, lexer, theme, ...) |
Constructor |
Progress
| Method | Description |
|---|---|
Progress(**columns) |
Constructor |
progress.add_task(desc, total) |
Add task |
progress.update(task, advance) |
Update task |
Gradient
| Method | Description |
|---|---|
Gradient(*colors, angle, color1_pct, color2_pct) |
Constructor |
gradient.color_at(t) |
Color at position 0..1 |
gradient.get_color(x, y, w, h) |
Color at pixel |
gradient.generate(w, h) |
Generate color grid |
gradient.to_stops(n) |
Get color stops |
gradient.add_color(color, position) |
Add color |
gradient.remove_color(index) |
Remove color |
gradient.angle |
Angle property (get/set) |
gradient.colors |
List of colors |
LinearGradient(...) |
Linear gradient |
RadialGradient(...) |
Radial gradient |
ConicGradient(..., start_angle) |
Conic gradient |
gradient(*colors, angle=0) |
Factory function |
Spinner
| Method | Description |
|---|---|
Spinner(name, text, speed, style) |
Constructor |
spinner.start() / stop() |
Start/stop |
spinner.update(text, color) |
Update |
Installation
pip install libtodraw
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file libtodraw-1.0.2.tar.gz.
File metadata
- Download URL: libtodraw-1.0.2.tar.gz
- Upload date:
- Size: 133.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b6007bf14303712638c2b6580e8ea6f02ffaf0fe0d422cc6c076074e1faab1dc
|
|
| MD5 |
3386727060db77a71da79ba999898349
|
|
| BLAKE2b-256 |
385b2d09639f2581e881641196398fb8df0d7326faa524ea31a0d7d59ecffb7a
|
File details
Details for the file libtodraw-1.0.2-py3-none-any.whl.
File metadata
- Download URL: libtodraw-1.0.2-py3-none-any.whl
- Upload date:
- Size: 55.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1bfb76375f5d5ecfa1df2bf337bd8d0e272e1ca9eef9025c38f94c18930becd1
|
|
| MD5 |
3125d6f9005cbd2f9d9a848ef9d3009a
|
|
| BLAKE2b-256 |
ba6555c2d511dd37a297b887a2f7169f0dc31113b9c22d6730a9a68595dfac59
|