tui_prompts/
text_state.rs

1use 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}