4 releases
Uses new Rust 2024
| 0.2.2 | Sep 8, 2025 |
|---|---|
| 0.2.1 | Sep 8, 2025 |
| 0.2.0 | Sep 8, 2025 |
| 0.1.0 | Sep 8, 2025 |
#1352 in Text processing
49KB
410 lines
ansi-align
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
Widthtype 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 optionsleft(text: &str) -> String- Left align (no-op, returns original)center(text: &str) -> String- Center align textright(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
Widthprevent 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
thiserrorfor 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
thiserrorfor 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
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
at your option.
Dependencies
~2.5–4MB
~63K SLoC