fresh/primitives/
display_width.rs1pub use fresh_core::display_width::{char_width, str_width};
13
14pub trait DisplayWidth {
16 fn display_width(&self) -> usize;
18}
19
20impl DisplayWidth for str {
21 #[inline]
22 fn display_width(&self) -> usize {
23 str_width(self)
24 }
25}
26
27impl DisplayWidth for String {
28 #[inline]
29 fn display_width(&self) -> usize {
30 str_width(self)
31 }
32}
33
34#[inline]
38pub fn visual_column_at_byte(s: &str, byte_offset: usize) -> usize {
39 s[..byte_offset.min(s.len())].chars().map(char_width).sum()
40}
41
42#[inline]
48pub fn byte_offset_at_visual_column(s: &str, visual_col: usize) -> usize {
49 let mut current_col = 0;
50 for (byte_idx, ch) in s.char_indices() {
51 if current_col >= visual_col {
52 return byte_idx;
53 }
54 current_col += char_width(ch);
55 }
56 s.len()
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62
63 #[test]
64 fn test_ascii_width() {
65 assert_eq!(str_width("Hello"), 5);
66 assert_eq!(str_width(""), 0);
67 assert_eq!(str_width(" "), 1);
68 }
69
70 #[test]
71 fn test_cjk_width() {
72 assert_eq!(str_width("你好"), 4);
74 assert_eq!(str_width("你好世界"), 8);
75
76 assert_eq!(str_width("月"), 2);
78 assert_eq!(str_width("日本"), 4);
79
80 assert_eq!(str_width("한글"), 4);
82 }
83
84 #[test]
85 fn test_emoji_width() {
86 assert_eq!(str_width("🚀"), 2);
88 assert_eq!(str_width("🎉"), 2);
89 assert_eq!(str_width("🚀🎉"), 4);
90 }
91
92 #[test]
93 fn test_mixed_width() {
94 assert_eq!(str_width("Hello你好"), 5 + 4);
96 assert_eq!(str_width("a你b"), 1 + 2 + 1);
97
98 assert_eq!(str_width("Hi🚀"), 2 + 2);
100 }
101
102 #[test]
103 fn test_char_width() {
104 assert_eq!(char_width('a'), 1);
105 assert_eq!(char_width('你'), 2);
106 assert_eq!(char_width('🚀'), 2);
107 }
108
109 #[test]
110 fn test_zero_width() {
111 assert_eq!(char_width('\0'), 0);
113 assert_eq!(char_width('\t'), 0); assert_eq!(char_width('\u{200B}'), 0);
117 }
118
119 #[test]
120 fn test_display_width_trait() {
121 let s = "你好";
122 assert_eq!(s.display_width(), 4);
123
124 let string = String::from("Hello🚀");
125 assert_eq!(string.display_width(), 7);
126 }
127}