ellipse/
lib.rs

1//! Truncate and ellipse strings in a human-friendly way.
2//!
3//! Uses unicode extended grapheme clusters.
4//!
5//! # Example
6//! ```
7//! use ellipse::Ellipse;
8//!
9//! let input = "🇩🇪🇬🇧🇮🇹🇫🇷";
10//! assert_eq!(&input.truncate_ellipse(2), "🇩🇪🇬🇧...");
11//! ```
12
13use std::borrow::Cow;
14use unicode_segmentation::UnicodeSegmentation;
15
16/// Truncate and ellipse strings in a human-friendly way.
17///
18/// # Example
19/// ```
20/// use ellipse::Ellipse;
21///
22/// let input = "🇩🇪🇬🇧🇮🇹🇫🇷";
23/// assert_eq!(&input.truncate_ellipse(2), "🇩🇪🇬🇧...");
24/// ```
25pub trait Ellipse {
26    type Output;
27
28    /// Truncate to a length of `len` extended grapheme clusters and place the given
29    /// ellipse string at the end when truncating.
30    ///
31    /// Truncating to a length of 0 will yield the empty element without an
32    /// attached ellipsis.
33    fn truncate_ellipse_with(&self, len: usize, ellipse: &str) -> Self::Output;
34
35    /// Truncate to a length of `len` extended grapheme clusters and add `...` at
36    /// the end of the string when truncating.
37    ///
38    /// Truncating to a length of 0 will yield the empty element without an
39    /// attached ellipsis.
40    fn truncate_ellipse(&self, len: usize) -> Self::Output {
41        self.truncate_ellipse_with(len, "...")
42    }
43}
44
45impl<'a> Ellipse for &'a str {
46    type Output = Cow<'a, str>;
47
48    fn truncate_ellipse_with(&self, len: usize, ellipse: &str) -> Self::Output {
49        if self.graphemes(true).count() <= len {
50            return Cow::Borrowed(self);
51        } else if len == 0 {
52            return Cow::Borrowed("");
53        }
54
55        let result = self
56            .graphemes(true)
57            .take(len)
58            .chain(ellipse.graphemes(true))
59            .collect();
60        Cow::Owned(result)
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn smoke() {
70        assert_eq!(&"Hello, World!".truncate_ellipse(3), "Hel...",);
71    }
72
73    #[test]
74    fn ellipse_with() {
75        assert_eq!(&"Hello, World!".truncate_ellipse_with(3, "---"), "Hel---");
76    }
77
78    #[test]
79    fn truncate_to_empty() {
80        assert_eq!(&"Hello, World!".truncate_ellipse(0), "");
81    }
82
83    #[test]
84    fn weird_chars() {
85        assert_eq!(
86            &"🇩🇪🇬🇧🇮🇹🇫🇷".truncate_ellipse(2),
87            "🇩🇪🇬🇧..."
88        );
89    }
90}