Something went wrong. Try again.
HEXWORK - A Lantern in the Deep: 3D ASCII terminal roguelike RPG in Rust.
Entirely designed and built by Muse Spark 1.3 to evaluate if I like the model.
Something went wrong. Try again.
2.1 kB · 62 lines
Rust
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263//! Terminal-cell-safe plain-text fitting shared by HUD and terminal chrome.
use unicode_width::UnicodeWidthChar;
/// Sanitize controls and fit plain text to exactly `width` terminal cells.////// C0 controls and DEL become spaces. Characters that would cross the cell/// boundary are omitted without splitting UTF-8. Zero-width characters are/// retained only after a visible base character, preventing detached leading/// combining marks. This is scalar-width fitting, not full grapheme shaping.#[must_use]pub fn fit_terminal_cells(value: &str, width: usize) -> String { let mut output = String::new(); let mut cells = 0usize; let mut has_base = false;
for mut character in value.chars() { if character <= '\u{1f}' || character == '\u{7f}' { character = ' '; } let character_width = UnicodeWidthChar::width(character).unwrap_or(0); if character_width == 0 { if has_base { output.push(character); } continue; } if cells.saturating_add(character_width) > width { break; } output.push(character); cells += character_width; has_base = true; } while cells < width { output.push(' '); cells += 1; } output}
#[cfg(test)]mod tests { use super::*; use unicode_width::UnicodeWidthStr;
#[test] fn fits_ascii_controls_wide_and_combining_scalars() { assert_eq!(fit_terminal_cells("lamp\u{1b}[31m", 8), "lamp [31"); assert_eq!(fit_terminal_cells("深淵灯", 2), "深"); assert_eq!(fit_terminal_cells("深淵灯", 5), "深淵 "); assert_eq!(fit_terminal_cells("e\u{301}lan", 3), "e\u{301}la"); assert_eq!(fit_terminal_cells("\u{301}a", 1), "a"); assert_eq!(fit_terminal_cells("ignored", 0), ""); for value in ["plain", "深淵灯", "e\u{301}lan", "\u{301}a"] { for width in 0..8 { let fitted = fit_terminal_cells(value, width); assert_eq!(UnicodeWidthStr::width(fitted.as_str()), width); } } }}