# ansi-align
[](https://crates.io/crates/ansi-align)
[](https://docs.rs/ansi-align)
[](https://github.com/sabry-awad97/ansi-align#license)
[](https://github.com/sabry-awad97/ansi-align/actions)
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`:
```toml
[dependencies]
ansi-align = "0.2.1"
```
For CLI tool development with enhanced error handling:
```toml
[dev-dependencies]
ansi-align = "0.2.1"
thiserror = "2.0"
clap = { version = "4.5", features = ["derive", "color"] }
colored = "3.0"
```
## Quick Start
```rust
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
```rust
use ansi_align::{ansi_align_with_options, Alignment, AlignOptions};
.with_split("|") // Custom line separator
.with_pad('.'); // Custom padding character
let result = ansi_align_with_options(text, &options);
### ANSI Escape Sequences
The library correctly handles ANSI escape sequences by ignoring them during width calculation:
```rust
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:
```rust
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`
```rust
pub enum Alignment {
Left,
Center,
Right,
}
```
#### `Width`
A type-safe wrapper for display width values:
```rust
let width = Width::new(42);
let value = width.get(); // Returns usize
```
#### `AlignOptions`
Configuration for alignment behavior:
```rust
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:
```rust
// 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:
```rust
// 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:
```bash
# 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:
```bash
$ 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:
📋 Menu Example:
Center aligned menu:
🏠 Home
📋 About Us
📞 Contact
⚙️ Settings
```
### Error Handling
The CLI provides clear, actionable error messages:
```bash
# 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
```rust
use ansi_align::center;
let menu = "Home\nAbout Us\nContact\nServices";
let aligned_menu = center(menu);
println!("{}", aligned_menu);
```
### Code Block Alignment
```rust
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
```rust
use ansi_align::{ansi_align_with_options, Alignment, AlignOptions};
.with_split("|")
.with_pad('_');
let result = ansi_align_with_options(data, options);
```
## Development
### Running Tests
```bash
cargo test
```
### Running the CLI Tool
```bash
# 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
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))
- MIT license ([LICENSE-MIT](LICENSE-MIT))
at your option.