basalt_tui/
text_counts.rs

1/// A wrapper type representing the number of characters in a string. **All** characters are
2/// counted for.
3///
4/// Character count can be created from an `usize` directly or computed from a `&str`.
5#[derive(Default, Clone, Debug, PartialEq)]
6pub struct CharCount(usize);
7
8impl From<usize> for CharCount {
9    fn from(value: usize) -> Self {
10        Self(value)
11    }
12}
13
14impl From<&str> for CharCount {
15    fn from(value: &str) -> Self {
16        value.chars().count().into()
17    }
18}
19
20impl From<CharCount> for usize {
21    fn from(value: CharCount) -> Self {
22        value.0
23    }
24}
25
26/// A wrapper type representing the number of words in a string.
27///
28/// Can be created from a `usize` directly or computed from a `&str` by counting the number of
29/// whitespace-separated words, after removing special markdown characters.
30///
31/// markdown characters: * _ ` < > ? ! [ ] ( ) = ~ # +
32#[derive(Default, Clone, Debug, PartialEq)]
33pub struct WordCount(usize);
34
35impl From<WordCount> for usize {
36    fn from(value: WordCount) -> Self {
37        value.0
38    }
39}
40
41impl From<usize> for WordCount {
42    fn from(value: usize) -> Self {
43        Self(value)
44    }
45}
46
47impl From<&str> for WordCount {
48    fn from(value: &str) -> Self {
49        let special_symbols = [
50            '*', '_', '`', '<', '>', '?', '!', '[', ']', '(', ')', '=', '~', '#', '+',
51        ];
52
53        value
54            .replace(special_symbols, "")
55            .split_whitespace()
56            .count()
57            .into()
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64    use indoc::indoc;
65
66    #[test]
67    fn test_text_counts() {
68        let tests = [
69            (
70                indoc! {r#"# Heading 1
71
72                ## Heading 2
73
74                ### Heading 3
75
76                #### Heading 4
77
78                ##### Heading 5
79
80                ###### Heading 6"#},
81                (WordCount(12), CharCount(91)),
82            ),
83            (
84                indoc! { r#"## Tasks
85
86                - [ ] Task
87
88                - [x] Completed task
89
90                - [?] Completed task"#},
91                (WordCount(10), CharCount(64)),
92            ),
93            (
94                indoc! {r#"## Quotes
95
96                You _can_ quote text by adding a `>` symbols before the text.
97
98                > Human beings face ever more complex and urgent problems, and their effectiveness in dealing with these problems is a matter that is critical to the stability and continued progress of society.
99                >
100                >- Doug Engelbart, 1961"#},
101                (WordCount(47), CharCount(294)),
102            ),
103        ];
104
105        tests.into_iter().for_each(|(input, expected)| {
106            assert_eq!(
107                (WordCount::from(input), CharCount::from(input)),
108                expected,
109                "With input {input}"
110            )
111        });
112    }
113}