rusty-rich 0.3.0

Rich text and beautiful formatting in the terminal โ€” a Rust port of Python's Rich library
Documentation
<p align="center">
  <img src="assets/logo.svg" alt="rusty-rich logo" width="600"/>
</p>

<p align="center">
  <strong>Rich text and beautiful formatting for the terminal โ€” a Rust port of Python's <a href="https://github.com/Textualize/rich">Rich</a> library.</strong>
</p>

<p align="center">
  <a href="https://crates.io/crates/rusty-rich"><img src="https://img.shields.io/crates/v/rusty-rich?color=F74C00" alt="crates.io"></a>
  <a href="https://docs.rs/rusty-rich"><img src="https://img.shields.io/docsrs/rusty-rich?color=F74C00" alt="docs.rs"></a>
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT"></a>
  <a href="#"><img src="https://img.shields.io/badge/tests-197%20passed-brightgreen" alt="tests"></a>
</p>

---

## โœจ Features

- ๐ŸŽจ **Style** โ€” foreground/background colors, bold, italic, underline, dim, blink, reverse, strikethrough, overline, conceal, frame, encircle, links
- ๐Ÿ“ **Console markup** โ€” `[bold red]text[/bold red]` BBCode-like inline styling
- ๐ŸŽฏ **256 named colors** โ€” full ANSI 256-color palette with aliases, hex, RGB, auto-downgrade
- ๐ŸŽญ **170+ theme styles** โ€” repr, json, markdown, logging, traceback, rule, bar, progress, table, tree, syntax, prompt categories

- ๐Ÿ“Š **Table** โ€” tabular data with headers, footers, colspan/rowspan, column alignment, sections, 17 box styles
- ๐ŸŒฒ **Tree** โ€” hierarchical tree rendering with Unicode guides
- ๐Ÿ“ฆ **Panel** โ€” bordered containers with titles, subtitles
- โž– **Rule** โ€” horizontal dividers with optional titles
- ๐Ÿ“ **Padding & Align** โ€” CSS-style padding and alignment helpers
- ๐Ÿ“‹ **Columns** โ€” side-by-side layout
- ๐Ÿ—‚๏ธ **Layout** โ€” recursive split-pane layout with ratio sizing

- โณ **Progress** โ€” multi-task progress bars with 11 column types, file tracking, `track()` iterator
- ๐Ÿ”„ **Spinner** โ€” 55 animated spinners with case-insensitive name lookup
- ๐Ÿ“Œ **Status** โ€” spinner + message with in-place update
- ๐Ÿ”„ **Live** โ€” auto-updating displays with alt-screen, transient mode, stdout/stderr redirect via `LiveWriter`

- ๐ŸŒˆ **Syntax highlighting** โ€” powered by syntect (100+ languages)
- ๐Ÿ“ **Markdown** โ€” headings, code blocks, lists, blockquotes, links, **tables**
- ๐Ÿ“‹ **JSON** โ€” pretty-printed, syntax-highlighted JSON
- ๐Ÿ” **Logging** โ€” Rich-formatted log records via the `log` crate

- ๐Ÿ–ผ๏ธ **Box drawing** โ€” 17 box styles (rounded, square, heavy, double, ASCII, etc.)
- ๐Ÿ–ฅ๏ธ **Screen / Alt-screen** โ€” full-screen terminal applications with `ScreenContext`
- โŒจ๏ธ **Prompts** โ€” `Prompt`, `IntPrompt`, `FloatPrompt`, `Confirm`, `Select<T>`, password mode
- ๐Ÿ”ด **Traceback** โ€” rich exception rendering with locals, source code, frame suppression, panic hook
- ๐Ÿ“ค **HTML & SVG export** โ€” capture console output for the web
- ๐Ÿงฉ **Segment utilities** โ€” simplify, split_lines, strip_styles, strip_links, align, divide, set_shape, filter_control

## ๐Ÿ“ฆ Installation

```toml
[dependencies]
rusty-rich = "0.2"
```

## ๐Ÿš€ Quick Start

```rust
use rusty_rich::{
    Console, Panel, Table, Column, Rule, Tree,
    Style, Color, AlignMethod, Padding,
};

fn main() {
    let mut console = Console::new();

    // Print with markup
    console.print_str("[bold green]Hello, [red]World![/red][/bold green]");

    // Create a panel with a title
    let panel = Panel::new("Hello inside a rounded box!")
        .title("My Panel")
        .border_style(Style::new().color(Color::parse("cyan").unwrap()));
    console.println(&panel);

    // Create a table
    let mut table = Table::new();
    table.add_column(Column::new("Name").justify(AlignMethod::Left));
    table.add_column(Column::new("Age").justify(AlignMethod::Right));
    table.add_row_str("Alice", "30");
    table.add_row_str("Bob", "25");
    console.println(&table);

    // Create a tree
    let mut tree = Tree::new("Root");
    tree.add("Child 1").add("Grandchild");
    tree.add("Child 2");
    console.println(&tree);

    // Draw a rule
    console.rule("Section Break", None, None, None);
}
```

## ๐ŸŽฏ Colors (256 names)

```rust
use rusty_rich::{Color, Style};

// Named colors โ€” 256 ANSI palette
let red = Color::parse("red").unwrap();
let hot_pink = Color::parse("hot_pink").unwrap();
let steel_blue = Color::parse("steel_blue").unwrap();
let grey53 = Color::parse("grey53").unwrap();

// Hex / RGB
let orange = Color::from_hex("#FF6600").unwrap();
let custom = Color::from_rgb(100, 200, 50);

// TrueColor โ†’ 8-bit โ†’ Standard auto-downgrade
let style = Style::new()
    .color(Color::parse("#FF6600").unwrap())
    .bgcolor(Color::parse("#1E1E2E").unwrap())
    .bold(true)
    .italic(true);
```

## ๐Ÿ“Š Table with Colspan & Rowspan

```rust
use rusty_rich::{Table, Column, Cell};

let mut table = Table::new().title("User Report");
table.add_column(Column::new("Name"));
table.add_column(Column::new("Details").colspan(2));  // spans 2 columns
table.add_column(Column::new("Role"));                  // skipped by colspan above

let row = vec![
    Cell::new("Alice"),
    Cell::new("Engineer").colspan(2),
];
table.add_row(row);
```

## โณ Progress Bars

```rust
use rusty_rich::Progress;
use std::thread;
use std::time::Duration;

let mut progress = Progress::new();
let task_id = progress.add_task("Downloading...", Some(100.0));

for i in 0..=100 {
    progress.update(task_id, i as f64);
    print!("\r{}", progress.render(80));
    thread::sleep(Duration::from_millis(20));
}
println!();

// Or use the `track()` convenience with an iterator
let items: Vec<_> = (0..100).collect();
let tracker = progress.track(items, "Processing", None);
for item in tracker {
    // process item โ€” progress auto-advances
}
```

## ๐Ÿ“ Markdown (with tables)

```rust
use rusty_rich::render_markdown;
use rusty_rich::Console;

let md = render_markdown("
# Hello

| Name  | Age |
|-------|-----|
| Alice | 30  |
| Bob   | 25  |

- list item 1
- list item 2
");

let console = Console::new();
console.println(&md);
```

## โŒจ๏ธ Interactive Prompts

```rust
use rusty_rich::{Prompt, Confirm, IntPrompt, Select};

// String input
let name = Prompt::ask_with("Enter your name").unwrap();

// Password input (masked with *)
let password = Prompt::new("Password").password(true).ask().unwrap();

// Confirmation with default
let ok = Confirm::ask_with("Continue?", true).unwrap();

// Integer with validation
let age = IntPrompt::ask_with("Enter age").unwrap();

// Pick from numbered choices
let choice = Select::new("Pick a color")
    .choice("Red", "red")
    .choice("Green", "green")
    .choice("Blue", "blue")
    .ask()
    .unwrap();
```

## ๐Ÿ”„ Live Display with Writer

```rust
use rusty_rich::{Console, Live, LiveWriter, Panel};
use std::io::Write;
use std::thread;
use std::time::Duration;

let mut live = Live::new(Panel::new("Starting...").title("Status"));
let mut writer = live.create_writer();
live.start().unwrap();

for i in 0..=100 {
    // Redirect writes through the live display
    writeln!(writer, "Processing item {}...", i).unwrap();
    live.update(Panel::new(format!("Progress: {}%", i)).title("Status")).unwrap();
    thread::sleep(Duration::from_millis(50));
}

live.stop().unwrap();
```

## ๐Ÿ”ด Rich Tracebacks

```rust
use rusty_rich::traceback;

// Install a global panic hook for rich tracebacks
traceback::install();

// Or render manually
let tb = Traceback::from_exception("MyError", "something went wrong", frames)
    .show_locals(true)
    .max_frames(5)
    .suppress(vec!["std::".into(), "core::".into()]);
```

## ๐Ÿ–ฅ๏ธ Full-Screen Apps

```rust
use rusty_rich::{Console, Screen, Live, Panel};
use std::thread;
use std::time::Duration;

let mut console = Console::new();
let mut screen = console.screen();  // enters alternate screen
screen.enter();

let mut live = Live::new(Panel::new("Loading...").title("Status"));
live.start().unwrap();

for i in 0..=100 {
    live.update(Panel::new(format!("Progress: {}%", i)).title("Status")).unwrap();
    thread::sleep(Duration::from_millis(50));
}

live.stop().unwrap();
screen.exit();  // restores terminal
```

## ๐ŸŽจ Box Styles (17 built-in)

| Style | Preview |
|---|---|
| `BOX_ROUNDED` | โ•ญโ”€โ•ฎ โ”‚ โ”‚ โ•ฐโ”€โ•ฏ |
| `BOX_SQUARE` | โ”Œโ”€โ” โ”‚ โ”‚ โ””โ”€โ”˜ |
| `BOX_HEAVY` | โ”โ”โ”“ โ”ƒ โ”ƒ โ”—โ”โ”› |
| `BOX_DOUBLE` | โ•”โ•โ•— โ•‘ โ•‘ โ•šโ•โ• |
| `BOX_DOUBLE_EDGE` | โ•”โ•โ•— โ•‘ โ”‚ โ•šโ•โ• |
| `BOX_HEAVY_EDGE` | โ”โ”โ”“ โ”ƒ โ”‚ โ”—โ”โ”› |
| `BOX_HEAVY_HEAD` | โ”โ”โ”“ โ”ƒ โ”ƒ โ””โ”€โ”˜ |
| `BOX_SIMPLE` | borderless with separators |
| `BOX_SIMPLE_HEAVY` | borderless with heavy separators |
| `BOX_MINIMAL` | minimal horizontal rules |
| `BOX_ASCII` | `+--+` ASCII-safe |
| `BOX_ASCII2` | `+--+` alternate ASCII |
| `BOX_MARKDOWN` | pipe-style markdown tables |
| โ€ฆ and 4 more |

## ๐Ÿงฉ Segment Utilities

```rust
use rusty_rich::segment::{self, Segment, Segments};

let segs: Segments = vec![
    Segment::styled("Hello ", Style::new().bold(true)),
    Segment::styled("World", Style::new().bold(true)),
].into();

// Combine adjacent same-styled segments
let simplified = segs.simplify();           // โ†’ one "Hello World" segment

// Split into lines
let lines = segment::split_lines(&segs.segments);

// Strip all styling
let plain = segment::strip_styles(&segs.segments);  // โ†’ "Hello World"

// Align vertically
let aligned = segment::align_middle(&lines, 80, 10, None);
```

## ๐Ÿ“‚ Module Map

```
src/
โ”œโ”€โ”€ lib.rs              # Crate root + re-exports
โ”œโ”€โ”€ console.rs          # Central rendering engine
โ”œโ”€โ”€ screen.rs           # Full-screen / alt-screen / ScreenContext
โ”œโ”€โ”€ color.rs            # TrueColor / 256 / Standard (256 names)
โ”œโ”€โ”€ style.rs            # 13 attributes + hyperlinks + metadata
โ”œโ”€โ”€ theme.rs            # 170+ named styles + stack
โ”œโ”€โ”€ segment.rs          # Segment + 9 utility functions
โ”œโ”€โ”€ text.rs             # Text with Span styling
โ”œโ”€โ”€ cells.rs            # Unicode cell width utilities
โ”œโ”€โ”€ measure.rs          # Width measurement protocol
โ”œโ”€โ”€ align.rs            # Horizontal + vertical alignment
โ”œโ”€โ”€ ratio.rs            # Proportional space distribution
โ”œโ”€โ”€ markup.rs           # BBCode-like markup parser
โ”œโ”€โ”€ highlighter.rs      # Regex/Repr highlighters
โ”‚
โ”œโ”€โ”€ panel.rs            # Bordered container
โ”œโ”€โ”€ table.rs            # Tabular data + colspan/rowspan
โ”œโ”€โ”€ tree.rs             # Hierarchical tree
โ”œโ”€โ”€ rule.rs             # Horizontal divider
โ”œโ”€โ”€ padding.rs          # CSS-style padding
โ”œโ”€โ”€ columns.rs          # Side-by-side layout
โ”œโ”€โ”€ layout.rs           # Split-pane layout
โ”œโ”€โ”€ box_drawing.rs      # 17 box/border styles
โ”‚
โ”œโ”€โ”€ progress.rs         # Multi-task progress + track()
โ”œโ”€โ”€ progress_columns.rs # 11 progress column types
โ”œโ”€โ”€ spinner.rs          # 55 animated spinners
โ”œโ”€โ”€ status.rs           # Spinner + message
โ”œโ”€โ”€ live.rs             # Auto-updating display + LiveWriter
โ”‚
โ”œโ”€โ”€ syntax.rs           # Syntax highlighting (syntect)
โ”œโ”€โ”€ markdown.rs         # Markdown rendering + table support
โ”œโ”€โ”€ json.rs             # Pretty-printed JSON
โ”œโ”€โ”€ logging.rs          # log crate integration
โ”œโ”€โ”€ prompt.rs           # 5 interactive prompt types
โ”œโ”€โ”€ traceback.rs        # Rich exception tracebacks
โ””โ”€โ”€ export.rs           # HTML / SVG / text export
```

## ๐Ÿ”ฌ Compared to Python Rich

| Feature | Python Rich | rusty-rich |
|---|---|---|
| Console + markup | โœ… | โœ… |
| Text / Span / Style | โœ… | โœ… |
| 256 named colors | โœ… | โœ… |
| Table (colspan/rowspan) | โœ… | โœ… |
| Panel / Rule / Tree | โœ… | โœ… |
| Layout / Columns | โœ… | โœ… |
| Progress (11 column types) | โœ… | โœ… |
| Live / Status | โœ… | โœ… |
| Syntax highlighting | โœ… | โœ… |
| Markdown (incl. tables) | โœ… | โœ… |
| JSON / Logging | โœ… | โœ… |
| Traceback (locals, suppress) | โœ… | โœ… |
| Screen / Alt-screen | โœ… | โœ… |
| Prompts (5 types) | โœ… | โœ… |
| 55+ Spinners | 80+ | 55 |
| 17 Box styles | 20 | 17 |
| HTML / SVG export | โœ… | โœ… |
| Segment utilities | โœ… | โœ… |
| LiveWriter / redirect | โœ… | โœ… |
| 170+ Theme styles | 170+ | 170+ |
| Pretty / Inspect | โœ… | โ€” |
| Emoji / ANSI decoder | โœ… | โ€” |
| Jupyter support | โœ… | โ€” |
| **Overall parity** | | **~72%** |

## ๐Ÿงช Testing

```bash
cargo test                    # 197 unit tests
cargo test --test battle_test # Integration / battle tests
```

## ๐Ÿ“„ License

MIT โ€” See [LICENSE](LICENSE) for details.

---

<p align="center">
  <sub>Inspired by <a href="https://github.com/Textualize/rich">Textualize/rich</a> โ€” the Python library that makes terminal output beautiful.</sub>
</p>