Skip to main content

atmos/os_lib/web_engine/
text_ellipsis.rs

1//! W3C CSS text-overflow: ellipsis 純粋計算モジュール
2//!
3//! W3C CSS Basic User Interface Module Level 3 §11.1 (text-overflow) に準拠した
4//! 文字列幅測定と省略記号(…)付加・LTR/RTL 切り詰め純粋ロジックを提供する。
5
6use alloc::format;
7use alloc::string::{String, ToString};
8use alloc::vec::Vec;
9
10/// 既定の省略記号(HORIZONTAL ELLIPSIS: U+2026)
11pub const DEFAULT_ELLIPSIS: &str = "…";
12
13/// テキストを与えられた利用可能幅に収まるよう、ellipsis(…)を付加して切り詰める(純粋関数)。
14///
15/// - `text`: 切り詰め対象の元の文字列
16/// - `available_w`: 利用可能な最大描画幅(px)
17/// - `ellipsis`: 省略記号(通常 "…")
18/// - `is_rtl`: true なら視覚上の先頭(左側)に省略記号を置き、先頭側を切り詰める
19/// - `measure_fn`: 文字列の描画幅(px)を返すクロージャ
20pub fn truncate_text_ellipsis<F>(
21    text: &str,
22    available_w: i32,
23    ellipsis: &str,
24    is_rtl: bool,
25    mut measure_fn: F,
26) -> String
27where
28    F: FnMut(&str) -> i32,
29{
30    if available_w <= 0 || text.is_empty() {
31        return String::new();
32    }
33    let full_w = measure_fn(text);
34    if full_w <= available_w {
35        return text.to_string();
36    }
37    let ellipsis_w = measure_fn(ellipsis);
38    let max_w = (available_w - ellipsis_w).max(0);
39    if max_w <= 0 {
40        return ellipsis.to_string();
41    }
42
43    if is_rtl {
44        let mut truncated = Vec::new();
45        let mut tw = 0i32;
46        for c in text.chars().rev() {
47            let mut cs = String::new();
48            cs.push(c);
49            let cw = measure_fn(&cs);
50            if tw + cw > max_w {
51                break;
52            }
53            truncated.push(c);
54            tw += cw;
55        }
56        let kept: String = truncated.into_iter().rev().collect();
57        format!("{}{}", ellipsis, kept)
58    } else {
59        let mut truncated = String::new();
60        let mut tw = 0i32;
61        for c in text.chars() {
62            let mut cs = String::new();
63            cs.push(c);
64            let cw = measure_fn(&cs);
65            if tw + cw > max_w {
66                break;
67            }
68            truncated.push(c);
69            tw += cw;
70        }
71        format!("{}{}", truncated, ellipsis)
72    }
73}