string-width 0.1.0

Accurate Unicode string width calculation for terminal applications, handling emoji, East Asian characters, combining marks, and ANSI escape sequences
Documentation
/// Terminal formatting and alignment examples
///
/// Run with: cargo run --example terminal_formatting
use string_width::DisplayWidth;

fn main() {
    println!("=== Terminal Formatting Examples ===\n");

    // Example 1: Text alignment in terminal
    let texts = vec!["Hello", "δ½ ε₯½", "🌍 World", "CafΓ©", "πŸ‡ΊπŸ‡Έ USA", "πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘¦ Family"];

    println!("Left-aligned (width 20):");
    for text in &texts {
        let width = text.display_width();
        let padding = 20_i32.saturating_sub(width as i32).max(0) as usize;
        println!("β”‚{}{}β”‚", text, " ".repeat(padding));
    }

    println!("\nRight-aligned (width 20):");
    for text in &texts {
        let width = text.display_width();
        let padding = 20_i32.saturating_sub(width as i32).max(0) as usize;
        println!("β”‚{}{}β”‚", " ".repeat(padding), text);
    }

    println!("\nCenter-aligned (width 20):");
    for text in &texts {
        let width = text.display_width();
        let total_padding = 20_i32.saturating_sub(width as i32).max(0) as usize;
        let left_padding = total_padding / 2;
        let right_padding = total_padding - left_padding;
        println!(
            "β”‚{}{}{}β”‚",
            " ".repeat(left_padding),
            text,
            " ".repeat(right_padding)
        );
    }

    // Example 2: Table formatting
    println!("\n=== Table Example ===");
    let data = vec![
        ("Name", "Country", "Greeting"),
        ("Alice", "πŸ‡ΊπŸ‡Έ USA", "Hello!"),
        ("η”°δΈ­", "πŸ‡―πŸ‡΅ Japan", "こんにけは"),
        ("JosΓ©", "πŸ‡ͺπŸ‡Έ Spain", "Β‘Hola!"),
        ("Ahmed", "πŸ‡ͺπŸ‡¬ Egypt", "Ω…Ψ±Ψ­Ψ¨Ψ§"),
    ];

    // Calculate column widths
    let col_widths = (0..3)
        .map(|col| {
            data.iter()
                .map(|row| match col {
                    0 => row.0.display_width(),
                    1 => row.1.display_width(),
                    2 => row.2.display_width(),
                    _ => 0,
                })
                .max()
                .unwrap_or(0)
        })
        .collect::<Vec<_>>();

    // Print table
    for (i, (name, country, greeting)) in data.iter().enumerate() {
        if i == 0 {
            // Header
            println!(
                "β”Œ{}┬{}┬{}┐",
                "─".repeat(col_widths[0] + 2),
                "─".repeat(col_widths[1] + 2),
                "─".repeat(col_widths[2] + 2)
            );
        }

        let name_padding = col_widths[0].saturating_sub(name.display_width());
        let country_padding = col_widths[1].saturating_sub(country.display_width());
        let greeting_padding = col_widths[2].saturating_sub(greeting.display_width());

        println!(
            "β”‚ {}{} β”‚ {}{} β”‚ {}{} β”‚",
            name,
            " ".repeat(name_padding),
            country,
            " ".repeat(country_padding),
            greeting,
            " ".repeat(greeting_padding)
        );

        if i == 0 {
            // Separator after header
            println!(
                "β”œ{}β”Ό{}β”Ό{}─",
                "─".repeat(col_widths[0] + 2),
                "─".repeat(col_widths[1] + 2),
                "─".repeat(col_widths[2] + 2)
            );
        }
    }
    println!(
        "β””{}β”΄{}β”΄{}β”˜",
        "─".repeat(col_widths[0] + 2),
        "─".repeat(col_widths[1] + 2),
        "─".repeat(col_widths[2] + 2)
    );

    // Example 3: Progress bar with emoji
    println!("\n=== Progress Bar Example ===");
    let tasks = vec![
        ("Downloading files", "πŸ“₯", 100),
        ("Processing data", "βš™οΈ", 75),
        ("Uploading results", "πŸ“€", 45),
        ("Sending notifications", "πŸ“§", 0),
    ];

    for (task, emoji, progress) in tasks {
        let bar_width = 30;
        let filled = (progress * bar_width) / 100;
        let empty = bar_width - filled;

        let task_display = format!("{} {}", emoji, task);
        let task_width = task_display.display_width();
        let task_padding = 25_i32.saturating_sub(task_width as i32).max(0) as usize;

        println!(
            "{}{} [{}{}] {:3}%",
            task_display,
            " ".repeat(task_padding),
            "β–ˆ".repeat(filled),
            "β–‘".repeat(empty),
            progress
        );
    }
}