1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//! String size measurement utilities for terminal display.
//!
//! This module provides functions for accurately measuring the display size of strings
//! in terminal cells. Unlike simple string length measurements, these functions properly
//! handle:
//!
//! - ANSI escape sequences (which are ignored in width calculations)
//! - Wide characters like CJK characters and emojis (which may occupy multiple cells)
//! - Multi-line strings
//!
//! # Why Use These Functions?
//!
//! Standard string length methods like `len()` or counting chars/graphemes won't give
//! accurate results for terminal display because:
//! - ANSI escape codes are counted but don't occupy display space
//! - Unicode characters can occupy 0, 1, or 2 terminal cells
//! - Different terminals may render characters differently
//!
//! # Examples
//!
//! ```
//! use lipgloss::size::{width, height, size};
//!
//! // ASCII text
//! assert_eq!(width("Hello"), 5);
//! assert_eq!(height("Hello"), 1);
//!
//! // Multi-line text
//! assert_eq!(width("Hello\nWorld!"), 6); // "World!" is longer
//! assert_eq!(height("Hello\nWorld!"), 2);
//!
//! // Wide characters (emoji)
//! let emoji_text = "Hello 👋";
//! assert!(width(emoji_text) > emoji_text.chars().count());
//! ```
use crate;
/// Width returns the cell width of characters in the string. ANSI sequences are
/// ignored and characters wider than one cell (such as Chinese characters and
/// emojis) are appropriately measured.
///
/// You should use this instead of `s.len()` or counting runes, as neither will
/// give you accurate results in a terminal.
///
/// For multi-line strings, this returns the width of the widest line.
///
/// # Arguments
///
/// * `s` - The string to measure
///
/// # Returns
///
/// The maximum width in terminal cells of any line in the string.
///
/// # Examples
///
/// ```
/// use lipgloss::size::width;
///
/// // Simple ASCII text
/// assert_eq!(width("Hello, World!"), 13);
///
/// // ANSI escape sequences are ignored
/// let colored = "\x1b[31mRed Text\x1b[0m";
/// assert_eq!(width(colored), 8); // Only "Red Text" is counted
///
/// // Wide characters (CJK)
/// assert_eq!(width("ä½ å¥½"), 4); // Each character is 2 cells wide
///
/// // Emoji (width may vary by terminal)
/// let emoji = "👋 Hello";
/// assert!(width(emoji) >= 7); // Emoji typically 2 cells + space + "Hello"
///
/// // Multi-line strings return the widest line
/// assert_eq!(width("Short\nMuch longer line\nMid"), 16);
/// ```
/// Height returns height of a string in cells. This is done simply by counting
/// `\n` characters. If your strings use `\r\n` for newlines you should convert
/// them to `\n` first, or write a separate function for measuring height.
///
/// # Arguments
///
/// * `s` - The string to measure
///
/// # Returns
///
/// The number of lines in the string (minimum of 1).
///
/// # Examples
///
/// ```
/// use lipgloss::size::height;
///
/// // Single line
/// assert_eq!(height("Hello, World!"), 1);
///
/// // Empty string still has height 1
/// assert_eq!(height(""), 1);
///
/// // Multi-line string
/// assert_eq!(height("Line 1\nLine 2\nLine 3"), 3);
///
/// // Trailing newline adds an extra line
/// assert_eq!(height("Hello\n"), 2);
///
/// // ANSI codes don't affect height
/// assert_eq!(height("\x1b[31mRed\x1b[0m\nBlue"), 2);
/// ```
///
/// # Note
///
/// This function counts `\n` characters. If your text uses `\r\n` (Windows-style)
/// line endings, you should normalize them to `\n` first:
///
/// ```
/// use lipgloss::size::height;
///
/// let windows_text = "Line 1\r\nLine 2\r\n";
/// let normalized = windows_text.replace("\r\n", "\n");
/// assert_eq!(height(&normalized), 3);
/// ```
/// Size returns the width and height of the string in cells. ANSI sequences are
/// ignored and characters wider than one cell (such as Chinese characters and
/// emojis) are appropriately measured.
///
/// This is a convenience function that combines [`width`] and [`height`].
///
/// # Arguments
///
/// * `s` - The string to measure
///
/// # Returns
///
/// A tuple of `(width, height)` where:
/// - `width` is the maximum line width in terminal cells
/// - `height` is the number of lines
///
/// # Examples
///
/// ```
/// use lipgloss::size::size;
///
/// // Single line
/// assert_eq!(size("Hello, World!"), (13, 1));
///
/// // Multi-line with different widths
/// let text = "Short\nThis is a longer line\nMedium";
/// assert_eq!(size(text), (21, 3));
///
/// // With ANSI codes and wide characters
/// let complex = "\x1b[1mBold\x1b[0m\nä½ å¥½ä¸–ç•Œ"; // "Hello World" in Chinese
/// let (w, h) = size(complex);
/// assert_eq!(h, 2);
/// assert!(w >= 8); // Chinese characters are wider
///
/// // Empty string
/// assert_eq!(size(""), (0, 1));
/// ```