1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use private_poker::constants::MAX_USER_INPUT_LENGTH;
/// Manages user inputs at the terminal.
pub struct UserInput {
/// Position of cursor in the input box.
pub char_idx: usize,
/// Current value of the input box.
pub value: String,
}
impl UserInput {
pub fn backspace(&mut self) {
// Method "remove" is not used on the saved text for deleting the selected char.
// Reason: Using remove on String works on bytes instead of the chars.
// Using remove would require special care because of char boundaries.
if self.char_idx != 0 {
// Getting all characters before the selected character.
let before_char_to_delete = self.value.chars().take(self.char_idx - 1);
// Getting all characters after selected character.
let after_char_to_delete = self.value.chars().skip(self.char_idx);
// Put all characters together except the selected one.
// By leaving the selected one out, it is forgotten and therefore deleted.
self.value = before_char_to_delete.chain(after_char_to_delete).collect();
self.move_left();
}
}
/// Returns the byte index based on the character position.
///
/// Since each character in a string can be contain multiple bytes, it's necessary to calculate
/// the byte index based on the index of the character.
fn byte_idx(&self) -> usize {
self.value
.char_indices()
.map(|(i, _)| i)
.nth(self.char_idx)
.unwrap_or(self.value.len())
}
pub fn clear(&mut self) {
self.char_idx = 0;
self.value.clear();
}
fn clamp_cursor(&self, new_cursor_pos: usize) -> usize {
new_cursor_pos.clamp(0, self.value.chars().count())
}
pub fn delete(&mut self) {
// Method "remove" is not used on the saved text for deleting the selected char.
// Reason: Using remove on String works on bytes instead of the chars.
// Using remove would require special care because of char boundaries.
if self.char_idx != self.value.len() {
// Getting all characters before the selected character.
let before_char_to_delete = self.value.chars().take(self.char_idx);
// Getting all characters after selected character.
let after_char_to_delete = self.value.chars().skip(self.char_idx + 1);
// Put all characters together except the selected one.
// By leaving the selected one out, it is forgotten and therefore deleted.
self.value = before_char_to_delete.chain(after_char_to_delete).collect();
}
}
pub fn input(&mut self, new_char: char) {
// Username length is about the same size as the largest allowed
if self.value.len() < MAX_USER_INPUT_LENGTH {
let idx = self.byte_idx();
self.value.insert(idx, new_char);
self.move_right();
}
}
pub fn jump_to_first(&mut self) {
self.char_idx = 0;
}
pub fn jump_to_last(&mut self) {
self.char_idx = self.value.len();
}
pub fn move_left(&mut self) {
let cursor_moved_left = self.char_idx.saturating_sub(1);
self.char_idx = self.clamp_cursor(cursor_moved_left);
}
pub fn move_right(&mut self) {
let cursor_moved_right = self.char_idx.saturating_add(1);
self.char_idx = self.clamp_cursor(cursor_moved_right);
}
pub fn new() -> Self {
Self {
char_idx: 0,
value: String::new(),
}
}
pub fn submit(&mut self) -> String {
let input = self.value.clone();
self.char_idx = 0;
self.value.clear();
input
}
}