1
use crate::utils;
2
use serde::Serialize;
3
use std::cmp;
4
use std::hash::Hash;
5
use std::str;
6
use unicode_segmentation::UnicodeSegmentation;
7

            
8
1037
#[derive(Debug, Default, Hash, Serialize)]
9
pub struct Row {
10
1034
    pub string: String,
11
}
12

            
13
impl From<&str> for Row {
14
1098
    fn from(s: &str) -> Self {
15
1098
        Self {
16
1098
            string: String::from(s),
17
        }
18
1098
    }
19
}
20

            
21
impl Row {
22
    #[must_use]
23
5
    pub fn render(&self, start: usize, end: usize, line_number: usize, x_offset: usize) -> String {
24
5
        let end = cmp::min(end, self.string.len()); // either stop at terminal end or string end
25
5
        let start = cmp::min(start, end);
26
5
        let mut visible = String::new();
27
18
        for grapheme in self.graphemes().skip(start).take(end - start) {
28
26
            visible.push_str(grapheme);
29
        }
30
9
        let prefix = if x_offset == 0 {
31
1
            "".to_string()
32
        } else {
33
4
            format!("{} ", utils::zfill(&line_number.to_string(), " ", x_offset))
34
        };
35
5
        format!("{}{}", prefix, visible)
36
5
    }
37

            
38
126
    pub fn chars(&self) -> std::str::Chars {
39
126
        self.string.chars()
40
126
    }
41

            
42
    #[must_use]
43
156
    pub fn graphemes(&self) -> unicode_segmentation::Graphemes {
44
156
        self.string[..].graphemes(true)
45
156
    }
46

            
47
    #[must_use]
48
4
    pub fn reversed(&self) -> String {
49
4
        self.graphemes().rev().collect()
50
4
    }
51

            
52
    #[must_use]
53
12
    pub fn is_whitespace(&self) -> bool {
54
24
        !self.string.chars().any(|c| !c.is_whitespace())
55
12
    }
56

            
57
    #[must_use]
58
190
    pub fn len(&self) -> usize {
59
190
        self.string[..].graphemes(true).count()
60
190
    }
61

            
62
    #[must_use]
63
1
    pub fn is_empty(&self) -> bool {
64
1
        self.len() == 0
65
1
    }
66

            
67
    #[must_use]
68
52
    pub fn nth_grapheme(&self, index: usize) -> &str {
69
52
        self.graphemes().nth(index).unwrap_or_default()
70
52
    }
71

            
72
    #[must_use]
73
114
    pub fn nth_char(&self, index: usize) -> char {
74
114
        self.chars().nth(index).unwrap_or_default()
75
114
    }
76

            
77
    #[must_use]
78
9
    pub fn num_words(&self) -> usize {
79
9
        self.string.unicode_words().count()
80
9
    }
81

            
82
    #[must_use]
83
8
    pub fn contains(&self, pattern: &str) -> bool {
84
8
        self.string.contains(pattern)
85
8
    }
86

            
87
    #[must_use]
88
6
    pub fn find_all(&self, pattern: &str) -> Vec<usize> {
89
6
        self.string
90
            .match_indices(pattern)
91
6
            .map(|item| item.0)
92
            .collect()
93
6
    }
94

            
95
    #[must_use]
96
9
    pub fn as_bytes(&self) -> &[u8] {
97
9
        self.string.as_bytes()
98
9
    }
99

            
100
10
    pub fn trim_end_inplace(&mut self) {
101
10
        self.string = String::from(self.string.trim_end());
102
10
    }
103

            
104
    /// Insert a character in the provided x index
105
41
    pub fn insert(&mut self, index: usize, c: char) {
106
48
        if index >= self.len() {
107
34
            self.string.push(c); // Append at the end of the row
108
        } else {
109
            // mid row edition
110
7
            let mut before: String = self.graphemes().take(index).collect();
111
7
            let after: String = self.graphemes().skip(index).collect();
112
7
            before.push(c);
113
7
            before.push_str(&after);
114
7
            self.string = before;
115
7
        }
116
41
    }
117

            
118
    /// Delete the character located at provided index
119
36
    pub fn delete(&mut self, index: usize) {
120
36
        if index >= self.len() {
121
            return;
122
        }
123
35
        let mut before: String = self.graphemes().take(index).collect();
124
35
        let after: String = self.graphemes().skip(index.saturating_add(1)).collect();
125
35
        before.push_str(&after);
126
35
        self.string = before;
127
36
    }
128

            
129
    /// Append a string at the end of the current one
130
9
    pub fn append(&mut self, other: &Self) {
131
9
        self.append_str(&other.string);
132
9
    }
133

            
134
37
    pub fn append_str(&mut self, s: &str) {
135
37
        self.string = format!("{}{}", self.string, s);
136
37
    }
137

            
138
    #[must_use]
139
5
    pub fn split(&mut self, at: usize) -> Self {
140
5
        let before: String = self.graphemes().take(at).collect();
141
5
        let after: String = self.graphemes().skip(at).collect();
142
5
        self.string = before;
143
5
        Self::from(&after[..])
144
5
    }
145
}
146

            
147
#[cfg(test)]
148
#[path = "./row_test.rs"]
149
mod row_test;