1use unicode_segmentation::UnicodeSegmentation;
2
3#[derive(Clone, Default)]
6pub struct Input {
7 chars: Vec<String>,
9 cursor_index: usize,
11}
12
13impl Input {
14 pub fn reset(&mut self) {
16 self.chars.clear();
17 self.cursor_index = 0;
18 }
19
20 #[must_use]
22 pub fn index(&self) -> usize {
23 self.cursor_index
24 }
25
26 #[must_use]
27 pub fn len(&self) -> usize {
28 self.chars.len()
29 }
30
31 #[must_use]
32 pub fn is_empty(&self) -> bool {
33 self.chars.is_empty()
34 }
35
36 #[must_use]
38 pub fn string(&self) -> String {
39 self.chars.join("")
40 }
41
42 #[must_use]
44 pub fn password(&self) -> String {
45 "*".repeat(self.len())
46 }
47
48 pub fn insert(&mut self, c: char) {
50 self.chars.insert(self.cursor_index, String::from(c));
51 self.cursor_index += 1;
52 }
53
54 pub fn cursor_start(&mut self) {
56 self.cursor_index = 0;
57 }
58
59 pub fn cursor_end(&mut self) {
61 self.cursor_index = self.len();
62 }
63
64 pub fn cursor_left(&mut self) {
66 if self.cursor_index > 0 {
67 self.cursor_index -= 1;
68 }
69 }
70
71 pub fn cursor_right(&mut self) {
73 if self.cursor_index < self.len() {
74 self.cursor_index += 1;
75 }
76 }
77
78 pub fn cursor_move(&mut self, index: usize) {
82 if index <= self.len() {
83 self.cursor_index = index
84 } else {
85 self.cursor_end()
86 }
87 }
88
89 pub fn delete_char_left(&mut self) {
91 if self.cursor_index > 0 && !self.chars.is_empty() {
92 self.chars.remove(self.cursor_index - 1);
93 self.cursor_index -= 1;
94 }
95 }
96
97 pub fn delete_chars_right(&mut self) {
99 self.chars = self
100 .chars
101 .iter()
102 .take(self.cursor_index)
103 .map(std::string::ToString::to_string)
104 .collect();
105 }
106
107 pub fn delete_line(&mut self) {
108 self.chars = vec![];
109 self.cursor_index = 0;
110 }
111
112 pub fn delete_left(&mut self) {
114 while self.cursor_index > 0 {
115 self.chars.remove(self.cursor_index.saturating_sub(1));
116 self.cursor_index -= 1;
117 if self.is_empty() || is_separator(&self.chars[self.cursor_index.saturating_sub(1)]) {
118 break;
119 }
120 }
121 }
122
123 pub fn replace(&mut self, content: &str) {
133 self.chars = UnicodeSegmentation::graphemes(content, true)
134 .collect::<Vec<&str>>()
135 .iter()
136 .map(|s| (*s).to_string())
137 .collect();
138 self.cursor_end();
139 }
140}
141
142fn is_separator(word: &str) -> bool {
143 matches!(
144 word,
145 " " | "/"
146 | "\\"
147 | "."
148 | ","
149 | ";"
150 | "!"
151 | "?"
152 | "%"
153 | "_"
154 | "-"
155 | "+"
156 | "*"
157 | "("
158 | ")"
159 | "{"
160 | "}"
161 | "["
162 | "]"
163 )
164}