use std::sync::OnceLock;
use regex::Regex;
fn ansi_escape_regex() -> &'static Regex {
static RE: OnceLock<Regex> = OnceLock::new();
RE.get_or_init(|| Regex::new(r"\x1b\[[0-9;]*m").expect("valid ANSI regex"))
}
#[must_use]
pub fn strip_ansi(text: &str) -> String {
ansi_escape_regex().replace_all(text, "").into_owned()
}
#[must_use]
pub fn display_width(text: &str) -> usize {
let stripped = strip_ansi(text);
stripped.chars().map(char_display_width).sum()
}
#[must_use]
pub fn char_display_width(c: char) -> usize {
if is_east_asian_wide_or_full(c) {
2
} else {
1
}
}
fn is_east_asian_wide_or_full(c: char) -> bool {
let cp = u32::from(c);
matches!(cp,
0x1100..=0x115F
| 0x2E80..=0x303E
| 0x3041..=0x33FF
| 0x3400..=0x4DBF
| 0x4E00..=0x9FFF
| 0xA000..=0xA4CF
| 0xAC00..=0xD7A3
| 0xF900..=0xFAFF
| 0xFE10..=0xFE6F
| 0xFF00..=0xFF60
| 0xFFE0..=0xFFE6
| 0x1F300..=0x1F64F
| 0x1F680..=0x1F6FF
| 0x1F700..=0x1F77F
| 0x1F780..=0x1F7FF
| 0x1F800..=0x1F8FF
| 0x1F900..=0x1F9FF
| 0x1FA00..=0x1FA6F
| 0x1FA70..=0x1FAFF
| 0x2600..=0x27BF
| 0x2B00..=0x2BFF
| 0x20000..=0x2FFFD
| 0x30000..=0x3FFFD
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn strip_ansi_removes_color_codes() {
assert_eq!(strip_ansi("\u{1b}[31mhi\u{1b}[0m"), "hi");
assert_eq!(strip_ansi("\u{1b}[1;91mbold red\u{1b}[0m"), "bold red");
}
#[test]
fn strip_ansi_preserves_plain_text() {
assert_eq!(strip_ansi("plain"), "plain");
assert_eq!(strip_ansi(""), "");
}
#[test]
fn display_width_plain_ascii() {
assert_eq!(display_width(""), 0);
assert_eq!(display_width("abc"), 3);
}
#[test]
fn display_width_strips_ansi() {
assert_eq!(display_width("\u{1b}[31mhi\u{1b}[0m"), 2);
}
#[test]
fn display_width_handles_emoji_keys() {
assert_eq!(display_width("\u{1F511}"), 2);
assert_eq!(display_width("\u{1F517}"), 2);
assert_eq!(display_width("\u{2B50}"), 2);
}
#[test]
fn display_width_handles_cjk() {
assert_eq!(display_width("你好"), 4);
}
#[test]
fn char_display_width_matches_table() {
assert_eq!(char_display_width('a'), 1);
assert_eq!(char_display_width('0'), 1);
assert_eq!(char_display_width(' '), 1);
assert_eq!(char_display_width('你'), 2);
assert_eq!(char_display_width('\u{1F511}'), 2);
}
}