wrap_ansi

Function wrap_ansi 

Source
pub fn wrap_ansi(
    string: &str,
    columns: usize,
    options: Option<WrapOptions>,
) -> String
Expand description

🎨 The main text wrapping function with full ANSI escape sequence support.

This is the primary function for wrapping text while intelligently preserving ANSI escape sequences for colors, styles, and hyperlinks. It handles Unicode characters correctly and provides flexible wrapping options for any use case.

§✨ Key Features

  • 🎨 ANSI Preservation: Colors and styles are maintained across line breaks
  • 🌍 Unicode Aware: Proper handling of CJK characters, emojis, and combining marks
  • πŸ”— Hyperlink Support: OSC 8 sequences remain clickable after wrapping
  • ⚑ High Performance: Optimized algorithms with pre-compiled regex patterns
  • πŸ› οΈ Flexible Options: Customizable wrapping behavior via WrapOptions

Β§Parameters

ParameterTypeDescription
string&strInput text (may contain ANSI sequences)
columnsusizeMaximum width in columns per line
optionsOption<WrapOptions>Wrapping configuration (uses defaults if None)

Β§Returns

A String with text wrapped to the specified width, with all ANSI sequences properly preserved and applied to each line as needed.

Β§Examples

Β§πŸ“ Basic Text Wrapping

use wrap_ansi::wrap_ansi;

let text = "The quick brown fox jumps over the lazy dog";
let wrapped = wrap_ansi(text, 20, None);
println!("{}", wrapped);
// Output:
// The quick brown fox
// jumps over the lazy
// dog

§🎨 Colored Text Wrapping

use wrap_ansi::wrap_ansi;

// Red text that maintains color across line breaks
let colored = "\u{001B}[31mThis is a long red text that will be wrapped properly\u{001B}[39m";
let wrapped = wrap_ansi(colored, 15, None);
println!("{}", wrapped);
// Each line will have: \u{001B}[31m[text]\u{001B}[39m
// Output (with colors):
// This is a long
// red text that
// will be wrapped
// properly
use wrap_ansi::wrap_ansi;

let link = "Visit \u{001B}]8;;https://example.com\u{0007}my website\u{001B}]8;;\u{0007} for more info";
let wrapped = wrap_ansi(link, 20, None);
// Hyperlinks remain clickable across line breaks

§🌍 Unicode and Emoji Support

use wrap_ansi::wrap_ansi;

// CJK characters are counted as 2 columns each
let chinese = "δ½ ε₯½δΈ–η•ŒοΌθΏ™ζ˜―δΈ€δΈͺ桋试。";
let wrapped = wrap_ansi(chinese, 10, None);

// Emojis work correctly too
let emoji = "Hello πŸ‘‹ World 🌍 with emojis πŸŽ‰";
let wrapped_emoji = wrap_ansi(emoji, 15, None);

Β§βš™οΈ Advanced Configuration

use wrap_ansi::{wrap_ansi, WrapOptions};

// Using builder pattern for clean configuration
let options = WrapOptions::builder()
    .hard_wrap(true)           // Break long words at boundary
    .trim_whitespace(false)    // Preserve all whitespace
    .word_wrap(true)           // Still respect word boundaries where possible
    .build();

let text = "supercalifragilisticexpialidocious word";
let wrapped = wrap_ansi(text, 10, Some(options));
// Output:
// supercalif
// ragilistic
// expialidoc
// ious word

§🎯 Real-World Use Cases

Β§Terminal Application Help Text

use wrap_ansi::{wrap_ansi, WrapOptions};

fn format_help_text(text: &str, terminal_width: usize) -> String {
    let options = WrapOptions::builder()
        .hard_wrap(false)  // Keep words intact for readability
        .trim_whitespace(true)  // Clean formatting
        .build();
     
    wrap_ansi(text, terminal_width.saturating_sub(4), Some(options))
}

Β§Code Syntax Highlighting

use wrap_ansi::wrap_ansi;

// Preserve syntax highlighting colors when wrapping code
let highlighted_code = "\u{001B}[34mfunction\u{001B}[39m \u{001B}[33mhello\u{001B}[39m() { \u{001B}[32m'world'\u{001B}[39m }";
let wrapped = wrap_ansi(highlighted_code, 25, None);
// Colors are preserved on each line

§🎨 ANSI Sequence Support

TypeCodesDescription
Foreground Colors30-37, 90-97Standard and bright text colors
Background Colors40-47, 100-107Standard and bright background colors
Text Styles1, 3, 4, 9Bold, italic, underline, strikethrough
Color Resets39, 49, 0Foreground, background, and full reset
HyperlinksOSC 8Clickable terminal links (OSC 8 sequences)
Custom SGRAnySupport for any Select Graphic Rendition codes

When text with ANSI codes is wrapped across multiple lines, each line gets complete escape sequences (opening codes at the start, closing codes at the end).

§🌍 Unicode Support Details

FeatureSupportDescription
Fullwidth Charactersβœ…CJK characters counted as 2 columns
Surrogate Pairsβœ…Proper handling of 4-byte Unicode sequences
Combining Charactersβœ…Don’t add to visual width
Emojiβœ…Correct width calculation for emoji sequences
RTL Text⚠️Basic support (visual width only)

§⚑ Performance Characteristics

  • Time Complexity: O(n) where n is input length
  • Space Complexity: O(n) for output string
  • Regex Compilation: Pre-compiled patterns for optimal performance
  • Memory Usage: Efficient string operations with capacity pre-allocation
  • ANSI Parsing: Optimized state machine for escape sequence detection

Β§πŸ”§ Performance Tips

use wrap_ansi::{wrap_ansi, WrapOptions};

// For maximum performance with trusted input:
let fast_options = WrapOptions {
    trim: false,      // Skip trimming operations
    hard: false,      // Avoid complex word breaking
    word_wrap: true,  // Use efficient word boundary detection
};

// For memory-constrained environments, process in chunks:
fn wrap_large_text(text: &str, columns: usize) -> String {
    text.lines()
        .map(|line| wrap_ansi(line, columns, None))
        .collect::<Vec<_>>()
        .join("\n")
}

§🚨 Important Notes

  • Column Width: Must be > 0 (use wrap_ansi_checked for validation)
  • Input Size: No built-in limits (use wrap_ansi_checked for protection)
  • Line Endings: \r\n is normalized to \n automatically
  • ANSI Sequences: Malformed sequences are passed through unchanged

Β§See Also

Examples found in repository?
examples/improved_features.rs (line 15)
3fn main() -> Result<(), WrapError> {
4    println!("=== Wrap-ANSI Improved Features Demo ===\n");
5
6    // 1. Builder Pattern for Options
7    println!("1. Builder Pattern for Options:");
8    let options = WrapOptions::builder()
9        .hard_wrap(true)
10        .trim_whitespace(false)
11        .word_wrap(true)
12        .build();
13
14    let text = "This is a verylongwordthatexceedslimit example";
15    let wrapped = wrap_ansi(text, 15, Some(options));
16    println!("Input: {}", text);
17    println!("Output:\n{}\n", wrapped);
18
19    // 2. Error Handling with Input Validation
20    println!("2. Error Handling:");
21
22    // Valid input
23    match wrap_ansi_checked("Hello world", 10, None) {
24        Ok(result) => println!("Valid input wrapped: {}", result.replace('\n', "\\n")),
25        Err(e) => println!("Error: {}", e),
26    }
27
28    // Invalid column width
29    match wrap_ansi_checked("Hello world", 0, None) {
30        Ok(result) => println!("Result: {}", result),
31        Err(e) => println!("Expected error: {}", e),
32    }
33
34    // Large input (simulated)
35    let large_text = "x".repeat(100);
36    match wrap_ansi_checked(&large_text, 10, None) {
37        Ok(result) => println!(
38            "Large input handled: {} chars -> {} chars",
39            large_text.len(),
40            result.len()
41        ),
42        Err(e) => println!("Error with large input: {}", e),
43    }
44
45    println!();
46
47    // 3. ANSI Color Preservation with Named Constants
48    println!("3. ANSI Color Preservation:");
49    let colored_text =
50        "\u{001B}[31mThis is red text that will be wrapped across multiple lines\u{001B}[39m";
51    let wrapped_colored = wrap_ansi(colored_text, 20, None);
52    println!("Colored text wrapped:");
53    println!("{}", wrapped_colored);
54    println!();
55
56    // 4. Hyperlink Preservation
57    println!("4. Hyperlink Preservation:");
58    let hyperlink_text = "\u{001B}]8;;https://example.com\u{0007}This is a clickable link that spans multiple lines\u{001B}]8;;\u{0007}";
59    let wrapped_hyperlink = wrap_ansi(hyperlink_text, 15, None);
60    println!("Hyperlink text wrapped:");
61    println!("{}", wrapped_hyperlink);
62    println!();
63
64    // 5. Performance with Complex ANSI Sequences
65    println!("5. Complex ANSI Sequences:");
66    let complex_text =
67        "\u{001B}[31m\u{001B}[42mRed text on green background\u{001B}[39m\u{001B}[49m normal text";
68    let wrapped_complex = wrap_ansi(complex_text, 12, None);
69    println!("Complex ANSI wrapped:");
70    println!("{}", wrapped_complex);
71    println!();
72
73    // 6. Unicode Support
74    println!("6. Unicode Support:");
75    let unicode_text = "Hello δΈ–η•Œ 🌍 こんにけは";
76    let wrapped_unicode = wrap_ansi(unicode_text, 10, None);
77    println!("Unicode text wrapped:");
78    println!("{}", wrapped_unicode);
79
80    Ok(())
81}