pub fn wrap_ansi(
string: &str,
columns: usize,
options: Option<WrapOptions>,
) -> StringExpand 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
| Parameter | Type | Description |
|---|---|---|
string | &str | Input text (may contain ANSI sequences) |
columns | usize | Maximum width in columns per line |
options | Option<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Β§π Hyperlink Preservation
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
| Type | Codes | Description |
|---|---|---|
| Foreground Colors | 30-37, 90-97 | Standard and bright text colors |
| Background Colors | 40-47, 100-107 | Standard and bright background colors |
| Text Styles | 1, 3, 4, 9 | Bold, italic, underline, strikethrough |
| Color Resets | 39, 49, 0 | Foreground, background, and full reset |
| Hyperlinks | OSC 8 | Clickable terminal links (OSC 8 sequences) |
| Custom SGR | Any | Support 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
| Feature | Support | Description |
|---|---|---|
| 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_checkedfor validation) - Input Size: No built-in limits (use
wrap_ansi_checkedfor protection) - Line Endings:
\r\nis normalized to\nautomatically - ANSI Sequences: Malformed sequences are passed through unchanged
Β§See Also
wrap_ansi_checked: Safe version with input validation and error handlingWrapOptions: Detailed configuration optionsWrapOptionsBuilder: Fluent interface for creating optionsWrapError: Error types for the checked version
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}