streampager/
util.rs

1//! Utilities.
2
3use std::borrow::Cow;
4
5use unicode_segmentation::UnicodeSegmentation;
6use unicode_width::UnicodeWidthStr;
7
8/// Returns the maximum width in characters of a number.
9pub(crate) fn number_width(number: usize) -> usize {
10    let mut width = 1;
11    let mut limit = 10;
12    while limit <= number {
13        limit *= 10;
14        width += 1;
15    }
16    width
17}
18
19/// Truncates a string to a column offset and width.
20pub(crate) fn truncate_string<'a>(
21    text: impl Into<Cow<'a, str>>,
22    offset: usize,
23    width: usize,
24) -> String {
25    let text = text.into();
26    if offset > 0 || width < text.width() {
27        let mut column = 0;
28        let mut maybe_start_index = None;
29        let mut maybe_end_index = None;
30        let mut start_pad = 0;
31        let mut end_pad = 0;
32        for (i, g) in text.grapheme_indices(true) {
33            let w = g.width();
34            if w != 0 {
35                if column >= offset && maybe_start_index.is_none() {
36                    maybe_start_index = Some(i);
37                    start_pad = column - offset;
38                }
39                if column + w > offset + width && maybe_end_index.is_none() {
40                    maybe_end_index = Some(i);
41                    end_pad = offset + width - column;
42                    break;
43                }
44                column += w;
45            }
46        }
47        let start_index = maybe_start_index.unwrap_or(text.len());
48        let end_index = maybe_end_index.unwrap_or(text.len());
49        format!(
50            "{0:1$.1$}{3}{0:2$.2$}",
51            "",
52            start_pad,
53            end_pad,
54            &text[start_index..end_index]
55        )
56    } else {
57        text.into_owned()
58    }
59}