summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-29 17:25:50 +0100
committersalmonik <salmonik@tuta.io>2026-10-29 17:25:50 +0100
commiteb68b1266ac833a00ee5a11b3e2d9a9d516d7a3c (patch)
tree0ab54d0a37e48676425fe419f1e427bce6455cc2
parentv2.1.1: color-code roulette numbers red and green (diff)
downloadzagan-bet-eb68b1266ac833a00ee5a11b3e2d9a9d516d7a3c.tar.gz
zagan-bet-eb68b1266ac833a00ee5a11b3e2d9a9d516d7a3c.zip
v2.1.2: ignore ANSI when measuring board height
-rw-r--r--Cargo.toml2
-rw-r--r--src/client/ui.rs24
-rw-r--r--tests/client_ui.rs17
3 files changed, 41 insertions, 2 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 08a4a3b..1725705 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "zagan-bet" 2name = "zagan-bet"
3version = "2.1.1" 3version = "2.1.2"
4edition = "2024" 4edition = "2024"
5 5
6[dependencies] 6[dependencies]
diff --git a/src/client/ui.rs b/src/client/ui.rs
index 11cedc7..1a35db1 100644
--- a/src/client/ui.rs
+++ b/src/client/ui.rs
@@ -159,7 +159,29 @@ pub fn parse_bet_arg(raw: &str) -> Result<u64, String> {
159/// ASCII, Latin diacritics, combining marks, CJK, and the common emoji ranges 159/// ASCII, Latin diacritics, combining marks, CJK, and the common emoji ranges
160/// without adding a dependency. 160/// without adding a dependency.
161pub fn display_width(text: &str) -> usize { 161pub fn display_width(text: &str) -> usize {
162 text.chars().map(char_width).sum() 162 let mut width = 0;
163 let mut chars = text.chars().peekable();
164
165 while let Some(character) = chars.next() {
166 if character == '\x1b' {
167 if chars.peek() == Some(&'[') {
168 chars.next();
169 // Skip CSI parameters until the final byte (@ through ~).
170 for character in chars.by_ref() {
171 if ('@'..='~').contains(&character) {
172 break;
173 }
174 }
175 } else {
176 // Two-character escape sequence.
177 chars.next();
178 }
179 continue;
180 }
181 width += char_width(character);
182 }
183
184 width
163} 185}
164 186
165fn char_width(c: char) -> usize { 187fn char_width(c: char) -> usize {
diff --git a/tests/client_ui.rs b/tests/client_ui.rs
index ea432e0..f5e3c0e 100644
--- a/tests/client_ui.rs
+++ b/tests/client_ui.rs
@@ -99,6 +99,23 @@ fn redraw_moves_up_by_line_count_minus_one() {
99} 99}
100 100
101#[test] 101#[test]
102fn display_width_ignores_ansi_sequences() {
103 assert_eq!(display_width("\x1b[31m18\x1b[0m"), 2);
104 assert_eq!(display_width("\x1b[1;31m[ 18 ]\x1b[0m"), 6);
105 assert_eq!(display_width("plain"), 5);
106}
107
108#[test]
109fn visual_line_count_ignores_ansi_sequences() {
110 let styled = format!("\x1b[31m{}\x1b[0m", "x".repeat(75));
111 assert_eq!(visual_line_count(&[styled], 72), 2);
112 assert_eq!(
113 visual_line_count(&["\x1b[31m18\x1b[0m".to_string()], 80),
114 1
115 );
116}
117
118#[test]
102fn visual_line_count_accounts_for_terminal_wrapping() { 119fn visual_line_count_accounts_for_terminal_wrapping() {
103 let lines = vec![ 120 let lines = vec![
104 "12345".to_string(), 121 "12345".to_string(),