ansi-align 0.2.2

Text alignment library with ANSI escape sequence and Unicode support
Documentation

ansi-align

Crates.io Documentation License Build Status

A Rust library for aligning text with proper support for ANSI escape sequences and Unicode characters.

Features

  • ANSI-aware alignment: Correctly handles text containing ANSI escape sequences (colors, formatting)
  • Unicode support: Properly calculates display width for Unicode characters including CJK characters
  • Multiple alignment options: Left, center, and right alignment
  • Customizable: Configure split strings and padding characters
  • Performance optimized: Single-pass processing with efficient memory usage
  • Type-safe: Uses a Width type for display width values

Installation

Add this to your Cargo.toml:

[dependencies]

ansi-align = "0.2.2"

For CLI tool development with enhanced error handling:

[dev-dependencies]

ansi-align = "0.2.2"

thiserror = "2.0"

clap = { version = "4.5", features = ["derive", "color"] }

colored = "3.0"

Quick Start

use ansi_align::{ansi_align, center, left, right};

// Basic alignment (defaults to center)
let text = "hello\nworld";
let centered = ansi_align(text);

// Specific alignment functions
let left_aligned = left("short\nlonger line");
let centered = center("short\nlonger line");
let right_aligned = right("short\nlonger line");

Advanced Usage

Custom Options

use ansi_align::{ansi_align_with_options, Alignment, AlignOptions};

let text = "line1|line2|line3";
let options = AlignOptions::new(Alignment::Right)
    .with_split("|")           // Custom line separator
    .with_pad('.');            // Custom padding character

let result = ansi_align_with_options(text, &options);
// Result: "..line1|..line2|..line3"

ANSI Escape Sequences

The library correctly handles ANSI escape sequences by ignoring them during width calculation:

use ansi_align::center;

let colored_text = "\x1b[31mred\x1b[0m\n\x1b[32mgreen text\x1b[0m";
let aligned = center(colored_text);
// ANSI codes are preserved but don't affect alignment

Unicode Characters

Wide Unicode characters (like CJK) are handled correctly:

use ansi_align::center;

let unicode_text = "\n古古古";
let aligned = center(unicode_text);
// Properly accounts for double-width characters

API Reference

Core Functions

  • ansi_align(text: &str) -> String - Center align text (default)
  • ansi_align_with_options(text: &str, opts: AlignOptions) -> String - Align with custom options
  • left(text: &str) -> String - Left align (no-op, returns original)
  • center(text: &str) -> String - Center align text
  • right(text: &str) -> String - Right align text

Types

Alignment

pub enum Alignment {
    Left,
    Center,
    Right,
}

Width

A type-safe wrapper for display width values:

let width = Width::new(42);
let value = width.get(); // Returns usize

AlignOptions

Configuration for alignment behavior:

pub struct AlignOptions {
    pub align: Alignment,    // Alignment type
    pub split: String,       // Line separator (default: "\n")
    pub pad: char,          // Padding character (default: ' ')
}

Builder methods:

  • AlignOptions::new(align: Alignment) - Create with alignment
  • .with_split(split: impl Into<String>) - Set custom line separator
  • .with_pad(pad: char) - Set custom padding character

Performance

  • Left alignment: Optimized as a no-op, returns input unchanged
  • Single pass: Text is processed once for optimal performance
  • Efficient padding: Uses optimized string creation for different padding sizes
  • Memory conscious: Minimal allocations with capacity pre-calculation
  • String processing: Optimized escape sequence handling reduces intermediate allocations
  • Width calculation: Efficient iterator-based approach without unnecessary collections

Architecture & Design

Library Design Principles

  • Type Safety: Custom types like Width prevent common errors
  • Zero-cost Abstractions: Performance-critical paths have minimal overhead
  • Composability: Functions can be easily combined and extended
  • Unicode First: Proper handling of complex text from the ground up

CLI Tool Architecture

The example CLI tool showcases production-ready Rust patterns:

// Custom error types with context
#[derive(Error, Debug)]
enum CliError {
    #[error("Failed to read file '{path}': {source}")]
    FileRead { path: String, source: std::io::Error },
    #[error("Failed to read from stdin: {0}")]
    StdinRead(std::io::Error),
    #[error("File not found: {0}")]
    FileNotFound(String),
}

// Configurable border rendering
struct BorderConfig {
    top_left: char,
    top_right: char,
    // ... other border characters
    padding: usize,
}

// Modular demo system
struct DemoSection {
    title: String,
    content: Box<dyn Fn()>,
}

Border Customization

The CLI tool features a configurable border system:

// Default Unicode box drawing characters
struct BorderConfig {
    top_left: '┌',     //    top_right: '┐',    //    bottom_left: '└',  //    bottom_right: '┘', //    horizontal: '─',   //    vertical: '│',     //    padding: 1,        // Space padding
}

Example output with borders:

┌───────┐
│ Hello │
│ World │
│ Rust  │
└───────┘

Key Improvements in v0.2.1

  • Enhanced Error Handling: Replaced generic errors with specific, actionable error types
  • Performance Optimizations: Reduced string allocations and improved processing efficiency
  • Better Separation of Concerns: Modular design with dedicated structs for different responsibilities
  • Improved Testability: Broke down large functions into focused, testable units
  • Configuration System: Extensible border styles and formatting options
  • Input Validation: Proper file existence checking and argument validation
  • Modular Demo System: Organized demo sections for better maintainability
  • Production Ready: Robust error handling and edge case management

CLI Tool

The crate includes a powerful, production-ready CLI tool with advanced features and robust error handling:

# Run the interactive demo to see all features

cargo run --example cli_tool -- --demo


# Align text from command line

cargo run --example cli_tool -- "Hello\nWorld\nRust" --align center --border


# Read from stdin with escape sequence processing

echo "Line 1\nLonger Line 2\nShort" | cargo run --example cli_tool -- - --align right --pad '.'


# Read from file with validation

cargo run --example cli_tool -- --file examples/sample.txt --align center --border


# Custom separator and padding

cargo run --example cli_tool -- "Name|Age|City" --split "|" --align center --pad '_'


# Quiet mode for scripting

cargo run --example cli_tool -- "data" --border --quiet

CLI Features

  • 🎨 Beautiful output with customizable colorful borders
  • 📁 Multiple input sources: command line arguments, stdin, or files
  • 🌈 ANSI color preservation maintains formatting in aligned output
  • 🌏 Full Unicode support including CJK and emoji characters
  • ⚙️ Highly customizable padding characters and line separators
  • 📋 Interactive demo showcasing all alignment capabilities
  • 🛡️ Robust error handling with descriptive error messages
  • Performance optimized with minimal memory allocations
  • 🔧 Production ready with proper validation and edge case handling
  • 🤫 Quiet mode for integration with scripts and pipelines

CLI Architecture

The CLI tool demonstrates modern Rust best practices:

  • Custom Error Types: Uses thiserror for type-safe, descriptive error handling
  • Modular Design: Separated concerns with dedicated structs for border rendering and demo sections
  • Performance Optimized: Efficient string processing and memory usage
  • Configurable: Extensible border styles and formatting options
  • Testable: Small, focused functions with single responsibilities

Enhanced Demo System

The CLI includes an interactive demo showcasing all features:

$ cargo run --example cli_tool -- --demo

🎨 ansi-align Demo - Beautiful Text Alignment


📝 Basic Alignment:

Left:

Hello

World

Rust


Center:

Hello

World

Rust


Right:

Hello

World

 Rust


🌈 ANSI Color Support:

Center aligned with colors:

 Red Text

Green Text

Blue Text


🌏 Unicode Support:

Right aligned Unicode:

        

    古古古

Hello 世界


⚙️ Custom Options:

Custom separator '|' and padding '.':

..Name|..Age|Location


📋 Menu Example:

Center aligned menu:

  🏠 Home

📋 About Us

📞 Contact

⚙️ Settings

Error Handling

The CLI provides clear, actionable error messages:

# File not found

$ cargo run --example cli_tool -- --file nonexistent.txt

Error: File not found: nonexistent.txt


# Invalid file permissions

$ cargo run --example cli_tool -- --file /protected/file.txt

Error: Failed to read file '/protected/file.txt': Permission denied

Examples

Simple Menu Alignment

use ansi_align::center;

let menu = "Home\nAbout Us\nContact\nServices";
let aligned_menu = center(menu);
println!("{}", aligned_menu);

Code Block Alignment

use ansi_align::right;

let code = "if x:\n    return y\nelse:\n    return z";
let aligned_code = right(code);
println!("{}", aligned_code);

Custom Separator and Padding

use ansi_align::{ansi_align_with_options, Alignment, AlignOptions};

let data = "Name|Age|City";
let options = AlignOptions::new(Alignment::Center)
    .with_split("|")
    .with_pad('_');

let result = ansi_align_with_options(data, options);

Development

Running Tests

cargo test

Running the CLI Tool

# Interactive demo

cargo run --example cli_tool -- --demo


# Test with sample data

cargo run --example cli_tool -- "Hello\nWorld" --border --align center


# Test error handling

cargo run --example cli_tool -- --file nonexistent.txt

Code Quality

The project follows Rust best practices:

  • Error Handling: Uses thiserror for descriptive error types
  • Performance: Optimized string processing and memory usage
  • Testing: Comprehensive test coverage for edge cases
  • Documentation: Extensive inline documentation and examples
  • Modularity: Clean separation of concerns and reusable components

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

License

Licensed under either of

at your option.