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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
use clipboard::ClipboardProvider;
use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
/// Messages passed to the InputState
#[derive(Debug)]
pub enum Message {
/// Empty message, no state change happens. Used to avoid the use of [`Option<Message>`].
Empty,
/// Gain focus on the input
Focus,
/// Remove focus from the input
RemoveFocus,
/// Delete the character under the cursor
DeleteOnCursor,
/// Delete the character before the cursor
DeleteBeforeCursor,
/// Move the cursor to the left
MoveLeft,
/// Move the cursor to the left and start/continou text selection
MoveLeftWithSelection,
/// Move the cursor to the right
MoveRight,
/// Move the cursor to the right and start/continue the text selection
MoveRightWithSelection,
/// Jump the cursor to the end
JumpToEnd,
/// Jump the cursor to the end and seect everything in between the end and start position
JumpToEndWithSelection,
/// Jump the cursor to the start
JumpToStart,
/// Jump the cursor to the start and select everything in between the start and end position
JumpToStartWithSelection,
/// Character input
Char(char),
/// Insert a string at the current cursor position. If we have a selection, the selection will get replaced
Paste(String),
/// Toggle the insert mode
ToggleInsertMode,
/// Copy selected text or if there is no selection, the entire input value and add it to the clipboard
Copy,
/// Cut selected text or if there is no selection the entire input and add it to the clipboard
Cut,
//TODO: SelectAll
//TODO: SelectWord
//TODO: JumpToEndOfWord
//TODO: JumpToStartOfWord
}
impl From<Event> for Message {
fn from(value: Event) -> Self {
match value {
Event::FocusGained => Message::Focus,
Event::FocusLost => Message::RemoveFocus,
Event::Key(key) => key.into(),
Event::Mouse(_) => Message::Empty,
Event::Paste(str) => Message::Paste(str),
Event::Resize(_, _) => Message::Empty,
}
}
}
impl From<KeyEvent> for Message {
fn from(value: KeyEvent) -> Self {
if value.kind == KeyEventKind::Release {
Message::Empty
} else {
match value.code {
KeyCode::Backspace => Message::DeleteBeforeCursor,
KeyCode::Enter => Message::RemoveFocus,
KeyCode::Left => {
if value.modifiers == KeyModifiers::SHIFT {
Message::MoveLeftWithSelection
} else {
Message::MoveLeft
}
}
KeyCode::Right => {
if value.modifiers == KeyModifiers::SHIFT {
Message::MoveRightWithSelection
} else {
Message::MoveRight
}
}
KeyCode::Up => Message::Empty,
KeyCode::Down => Message::Empty,
KeyCode::Home => {
if value.modifiers == KeyModifiers::SHIFT {
Message::JumpToStartWithSelection
} else {
Message::JumpToStart
}
}
KeyCode::End => {
if value.modifiers == KeyModifiers::SHIFT {
Message::JumpToEndWithSelection
} else {
Message::JumpToEnd
}
}
KeyCode::PageUp => Message::Empty,
KeyCode::PageDown => Message::Empty,
KeyCode::Tab => Message::Char('\t'),
KeyCode::BackTab => Message::Empty,
KeyCode::Delete => Message::DeleteOnCursor,
KeyCode::Insert => Message::ToggleInsertMode,
KeyCode::F(_) => Message::Empty,
KeyCode::Char(c) => match c {
'c' => {
if value.modifiers == KeyModifiers::CONTROL {
Message::Copy
} else {
Message::Char('c')
}
}
'x' => {
if value.modifiers == KeyModifiers::CONTROL {
Message::Cut
} else {
Message::Char('x')
}
}
'v' => {
if value.modifiers == KeyModifiers::CONTROL {
match clipboard::ClipboardContext::new()
.and_then(|mut cc| cc.get_contents())
{
Ok(str) => Message::Paste(str),
Err(_) => Message::Empty,
}
} else {
Message::Char('v')
}
}
c => Message::Char(c),
},
KeyCode::Null => Message::Empty,
KeyCode::Esc => Message::RemoveFocus,
KeyCode::CapsLock => Message::Empty,
KeyCode::ScrollLock => Message::Empty,
KeyCode::NumLock => Message::Empty,
KeyCode::PrintScreen => Message::Empty,
KeyCode::Pause => Message::Empty,
KeyCode::Menu => Message::Empty,
KeyCode::KeypadBegin => Message::Empty,
KeyCode::Media(_) => Message::Empty,
KeyCode::Modifier(_) => Message::Empty,
}
}
}
}