ansi-align

Crates.ioansi-align
lib.rsansi-align
version0.2.2
created_at2025-09-08 00:12:46.547417+00
updated_at2025-09-08 01:11:56.630606+00
descriptionText alignment library with ANSI escape sequence and Unicode support
homepage
repositoryhttps://github.com/sabry-awad97/ansi-align
max_upload_size
id1828640
size85,788
Sabry Awad (sabry-awad97)

documentation

https://docs.rs/ansi-align

README

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.

Commit count: 7

cargo fmt