Skip to main content

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    use similar_asserts::assert_eq;
66
67    #[test]
68    fn test_text_counts() {
69        let tests = [
70            (
71                indoc! {r#"# Heading 1
72
73                ## Heading 2
74
75                ### Heading 3
76
77                #### Heading 4
78
79                ##### Heading 5
80
81                ###### Heading 6"#},
82                (WordCount(12), CharCount(91)),
83            ),
84            (
85                indoc! { r#"## Tasks
86
87                - [ ] Task
88
89                - [x] Completed task
90
91                - [?] Completed task"#},
92                (WordCount(10), CharCount(64)),
93            ),
94            (
95                indoc! {r#"## Quotes
96
97                You _can_ quote text by adding a `>` symbols before the text.
98
99                > 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.
100                >
101                >- Doug Engelbart, 1961"#},
102                (WordCount(47), CharCount(294)),
103            ),
104        ];
105
106        tests.into_iter().for_each(|(input, expected)| {
107            assert_eq!(
108                (WordCount::from(input), CharCount::from(input)),
109                expected,
110                "With input {input}"
111            )
112        });
113    }
114}