tui_prompts/
text_state.rs1use std::borrow::Cow;
2
3use crate::prelude::*;
4use crate::State;
5
6#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
7pub struct TextState<'a> {
8 status: Status,
9 focus: FocusState,
10 position: usize,
11 cursor: (u16, u16),
12 value: Cow<'a, str>,
13}
14
15impl<'a> TextState<'a> {
16 #[must_use]
17 pub const fn new() -> Self {
18 Self {
19 status: Status::Pending,
20 focus: FocusState::Unfocused,
21 position: 0,
22 cursor: (0, 0),
23 value: Cow::Borrowed(""),
24 }
25 }
26
27 #[must_use]
28 pub const fn with_status(mut self, status: Status) -> Self {
29 self.status = status;
30 self
31 }
32
33 #[must_use]
34 pub const fn with_focus(mut self, focus: FocusState) -> Self {
35 self.focus = focus;
36 self
37 }
38
39 #[must_use]
40 pub fn with_value(mut self, value: impl Into<Cow<'a, str>>) -> Self {
41 self.value = value.into();
42 self
43 }
44
45 #[must_use]
46 pub const fn is_finished(&self) -> bool {
47 self.status.is_finished()
48 }
49}
50
51impl State for TextState<'_> {
52 fn status(&self) -> Status {
53 self.status
54 }
55
56 fn status_mut(&mut self) -> &mut Status {
57 &mut self.status
58 }
59
60 fn focus_state_mut(&mut self) -> &mut FocusState {
61 &mut self.focus
62 }
63
64 fn focus_state(&self) -> FocusState {
65 self.focus
66 }
67
68 fn position(&self) -> usize {
69 self.position
70 }
71
72 fn position_mut(&mut self) -> &mut usize {
73 &mut self.position
74 }
75
76 fn cursor(&self) -> (u16, u16) {
77 self.cursor
78 }
79
80 fn cursor_mut(&mut self) -> &mut (u16, u16) {
81 &mut self.cursor
82 }
83
84 fn value(&self) -> &str {
85 &self.value
86 }
87
88 fn value_mut(&mut self) -> &mut String {
89 self.value.to_mut()
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use crate::{State, TextState};
96
97 #[test]
98 fn insert_multibyte_start() {
99 let mut test = TextState::new().with_value("äë");
100 test.move_start();
101 test.push('Ï');
102 assert_eq!(test.value(), "Ïäë");
103 assert_eq!(test.position(), 1);
104 }
105 #[test]
106 fn insert_multibyte_middle() {
107 let mut test = TextState::new().with_value("äë");
108 test.move_right();
109 test.push('Ï');
110 assert_eq!(test.value(), "äÏë");
111 assert_eq!(test.position(), 2);
112 }
113 #[test]
114 fn insert_multibyte_end() {
115 let mut test = TextState::new().with_value("äë");
116 test.move_end();
117 test.push('Ï');
118 assert_eq!(test.value(), "äëÏ");
119 assert_eq!(test.position(), 3);
120 }
121
122 #[test]
123 fn delete_multibyte_start() {
124 let mut test = TextState::new().with_value("äë");
125 test.move_start();
126 test.delete();
127 assert_eq!(test.value(), "ë");
128 assert_eq!(test.position(), 0);
129 }
130
131 #[test]
132 fn delete_multibyte_middle() {
133 let mut test = TextState::new().with_value("äë");
134 test.move_right();
135 test.delete();
136 assert_eq!(test.value(), "ä");
137 assert_eq!(test.position(), 1);
138 }
139
140 #[test]
141 fn delete_multibyte_end() {
142 let mut test = TextState::new().with_value("äë");
143 test.move_end();
144 test.delete();
145 assert_eq!(test.value(), "äë");
146 assert_eq!(test.position(), 2);
147 }
148
149 #[test]
150 fn backspace_multibyte_start() {
151 let mut test = TextState::new().with_value("äë");
152 test.move_start();
153 test.backspace();
154 assert_eq!(test.value(), "äë");
155 assert_eq!(test.position(), 0);
156 }
157
158 #[test]
159 fn backspace_multibyte_middle() {
160 let mut test = TextState::new().with_value("äë");
161 test.move_right();
162 test.backspace();
163 assert_eq!(test.value(), "ë");
164 assert_eq!(test.position(), 0);
165 }
166
167 #[test]
168 fn backspace_multibyte_end() {
169 let mut test = TextState::new().with_value("äë");
170 test.move_end();
171 test.backspace();
172 assert_eq!(test.value(), "ä");
173 assert_eq!(test.position(), 1);
174 }
175}