1use crossterm::event::{Event, KeyEvent, KeyEventKind};
2use serde::{Deserialize, Serialize};
3use std::fmt::{Display, Formatter};
4use strum_macros::EnumIter;
5
6#[derive(Debug)]
8pub enum Signal {
9 Success(String),
11 CtrlC, CtrlD, }
16
17#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, EnumIter)]
21pub enum EditCommand {
22 MoveToStart,
24
25 MoveToLineStart,
27
28 MoveToEnd,
30
31 MoveToLineEnd,
33
34 MoveLeft,
36
37 MoveRight,
39
40 MoveWordLeft,
42
43 MoveBigWordLeft,
45
46 MoveWordRight,
48
49 MoveWordRightStart,
51
52 MoveBigWordRightStart,
54
55 MoveWordRightEnd,
57
58 MoveBigWordRightEnd,
60
61 MoveToPosition(usize),
63
64 InsertChar(char),
66
67 InsertString(String),
69
70 InsertNewline,
75
76 ReplaceChar(char),
78
79 ReplaceChars(usize, String),
81
82 Backspace,
84
85 Delete,
87
88 CutChar,
90
91 BackspaceWord,
93
94 DeleteWord,
96
97 Clear,
99
100 ClearToLineEnd,
102
103 Complete,
105
106 CutCurrentLine,
108
109 CutFromStart,
111
112 CutFromLineStart,
114
115 CutToEnd,
117
118 CutToLineEnd,
120
121 CutWordLeft,
123
124 CutBigWordLeft,
126
127 CutWordRight,
129
130 CutBigWordRight,
132
133 CutWordRightToNext,
135
136 CutBigWordRightToNext,
138
139 PasteCutBufferBefore,
141
142 PasteCutBufferAfter,
144
145 UppercaseWord,
147
148 LowercaseWord,
150
151 CapitalizeChar,
153
154 SwitchcaseChar,
156
157 SwapWords,
159
160 SwapGraphemes,
162
163 Undo,
165
166 Redo,
168
169 CutRightUntil(char),
171
172 CutRightBefore(char),
174
175 MoveRightUntil(char),
177
178 MoveRightBefore(char),
180
181 CutLeftUntil(char),
183
184 CutLeftBefore(char),
186
187 MoveLeftUntil(char),
189
190 MoveLeftBefore(char),
192}
193
194impl Display for EditCommand {
195 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
196 match self {
197 EditCommand::MoveToStart => write!(f, "MoveToStart"),
198 EditCommand::MoveToLineStart => write!(f, "MoveToLineStart"),
199 EditCommand::MoveToEnd => write!(f, "MoveToEnd"),
200 EditCommand::MoveToLineEnd => write!(f, "MoveToLineEnd"),
201 EditCommand::MoveLeft => write!(f, "MoveLeft"),
202 EditCommand::MoveRight => write!(f, "MoveRight"),
203 EditCommand::MoveWordLeft => write!(f, "MoveWordLeft"),
204 EditCommand::MoveBigWordLeft => write!(f, "MoveBigWordLeft"),
205 EditCommand::MoveWordRight => write!(f, "MoveWordRight"),
206 EditCommand::MoveWordRightEnd => write!(f, "MoveWordRightEnd"),
207 EditCommand::MoveBigWordRightEnd => write!(f, "MoveBigWordRightEnd"),
208 EditCommand::MoveWordRightStart => write!(f, "MoveWordRightStart"),
209 EditCommand::MoveBigWordRightStart => write!(f, "MoveBigWordRightStart"),
210 EditCommand::MoveToPosition(_) => write!(f, "MoveToPosition Value: <int>"),
211 EditCommand::InsertChar(_) => write!(f, "InsertChar Value: <char>"),
212 EditCommand::InsertString(_) => write!(f, "InsertString Value: <string>"),
213 EditCommand::InsertNewline => write!(f, "InsertNewline"),
214 EditCommand::ReplaceChar(_) => write!(f, "ReplaceChar <char>"),
215 EditCommand::ReplaceChars(_, _) => write!(f, "ReplaceChars <int> <string>"),
216 EditCommand::Backspace => write!(f, "Backspace"),
217 EditCommand::Delete => write!(f, "Delete"),
218 EditCommand::CutChar => write!(f, "CutChar"),
219 EditCommand::BackspaceWord => write!(f, "BackspaceWord"),
220 EditCommand::DeleteWord => write!(f, "DeleteWord"),
221 EditCommand::Clear => write!(f, "Clear"),
222 EditCommand::ClearToLineEnd => write!(f, "ClearToLineEnd"),
223 EditCommand::Complete => write!(f, "Complete"),
224 EditCommand::CutCurrentLine => write!(f, "CutCurrentLine"),
225 EditCommand::CutFromStart => write!(f, "CutFromStart"),
226 EditCommand::CutFromLineStart => write!(f, "CutFromLineStart"),
227 EditCommand::CutToEnd => write!(f, "CutToEnd"),
228 EditCommand::CutToLineEnd => write!(f, "CutToLineEnd"),
229 EditCommand::CutWordLeft => write!(f, "CutWordLeft"),
230 EditCommand::CutBigWordLeft => write!(f, "CutBigWordLeft"),
231 EditCommand::CutWordRight => write!(f, "CutWordRight"),
232 EditCommand::CutBigWordRight => write!(f, "CutBigWordRight"),
233 EditCommand::CutWordRightToNext => write!(f, "CutWordRightToNext"),
234 EditCommand::CutBigWordRightToNext => write!(f, "CutBigWordRightToNext"),
235 EditCommand::PasteCutBufferBefore => write!(f, "PasteCutBufferBefore"),
236 EditCommand::PasteCutBufferAfter => write!(f, "PasteCutBufferAfter"),
237 EditCommand::UppercaseWord => write!(f, "UppercaseWord"),
238 EditCommand::LowercaseWord => write!(f, "LowercaseWord"),
239 EditCommand::SwitchcaseChar => write!(f, "SwitchcaseChar"),
240 EditCommand::CapitalizeChar => write!(f, "CapitalizeChar"),
241 EditCommand::SwapWords => write!(f, "SwapWords"),
242 EditCommand::SwapGraphemes => write!(f, "SwapGraphemes"),
243 EditCommand::Undo => write!(f, "Undo"),
244 EditCommand::Redo => write!(f, "Redo"),
245 EditCommand::CutRightUntil(_) => write!(f, "CutRightUntil Value: <char>"),
246 EditCommand::CutRightBefore(_) => write!(f, "CutRightBefore Value: <char>"),
247 EditCommand::MoveRightUntil(_) => write!(f, "MoveRightUntil Value: <char>"),
248 EditCommand::MoveRightBefore(_) => write!(f, "MoveRightBefore Value: <char>"),
249 EditCommand::CutLeftUntil(_) => write!(f, "CutLeftUntil Value: <char>"),
250 EditCommand::CutLeftBefore(_) => write!(f, "CutLeftBefore Value: <char>"),
251 EditCommand::MoveLeftUntil(_) => write!(f, "MoveLeftUntil Value: <char>"),
252 EditCommand::MoveLeftBefore(_) => write!(f, "MoveLeftBefore Value: <char>"),
253 }
254 }
255}
256
257impl EditCommand {
258 pub fn edit_type(&self) -> EditType {
261 match self {
262 EditCommand::MoveToStart
264 | EditCommand::MoveToEnd
265 | EditCommand::MoveToLineStart
266 | EditCommand::MoveToLineEnd
267 | EditCommand::MoveToPosition(_)
268 | EditCommand::MoveLeft
269 | EditCommand::MoveRight
270 | EditCommand::MoveWordLeft
271 | EditCommand::MoveBigWordLeft
272 | EditCommand::MoveWordRight
273 | EditCommand::MoveWordRightStart
274 | EditCommand::MoveBigWordRightStart
275 | EditCommand::MoveWordRightEnd
276 | EditCommand::MoveBigWordRightEnd
277 | EditCommand::MoveRightUntil(_)
278 | EditCommand::MoveRightBefore(_)
279 | EditCommand::MoveLeftUntil(_)
280 | EditCommand::MoveLeftBefore(_) => EditType::MoveCursor,
281
282 EditCommand::InsertChar(_)
284 | EditCommand::Backspace
285 | EditCommand::Delete
286 | EditCommand::CutChar
287 | EditCommand::InsertString(_)
288 | EditCommand::InsertNewline
289 | EditCommand::ReplaceChar(_)
290 | EditCommand::ReplaceChars(_, _)
291 | EditCommand::BackspaceWord
292 | EditCommand::DeleteWord
293 | EditCommand::Clear
294 | EditCommand::ClearToLineEnd
295 | EditCommand::Complete
296 | EditCommand::CutCurrentLine
297 | EditCommand::CutFromStart
298 | EditCommand::CutFromLineStart
299 | EditCommand::CutToLineEnd
300 | EditCommand::CutToEnd
301 | EditCommand::CutWordLeft
302 | EditCommand::CutBigWordLeft
303 | EditCommand::CutWordRight
304 | EditCommand::CutBigWordRight
305 | EditCommand::CutWordRightToNext
306 | EditCommand::CutBigWordRightToNext
307 | EditCommand::PasteCutBufferBefore
308 | EditCommand::PasteCutBufferAfter
309 | EditCommand::UppercaseWord
310 | EditCommand::LowercaseWord
311 | EditCommand::SwitchcaseChar
312 | EditCommand::CapitalizeChar
313 | EditCommand::SwapWords
314 | EditCommand::SwapGraphemes
315 | EditCommand::CutRightUntil(_)
316 | EditCommand::CutRightBefore(_)
317 | EditCommand::CutLeftUntil(_)
318 | EditCommand::CutLeftBefore(_) => EditType::EditText,
319
320 EditCommand::Undo | EditCommand::Redo => EditType::UndoRedo,
321 }
322 }
323}
324
325#[derive(PartialEq, Eq)]
328pub enum EditType {
329 MoveCursor,
331 UndoRedo,
333 EditText,
335}
336
337#[derive(Debug)]
340pub enum UndoBehavior {
341 InsertCharacter(char),
343 Backspace(Option<char>),
346 Delete(Option<char>),
349 MoveCursor,
351 HistoryNavigation,
353 CreateUndoPoint,
356 UndoRedo,
358}
359
360impl UndoBehavior {
361 pub fn create_undo_point_after(&self, previous: &UndoBehavior) -> bool {
364 use UndoBehavior as UB;
365 match (previous, self) {
366 (_, UB::MoveCursor) => false,
368 (UB::HistoryNavigation, UB::HistoryNavigation) => false,
369 (UB::InsertCharacter(c_prev), UB::InsertCharacter(c_new)) => {
372 (*c_prev == '\n' || *c_prev == '\r')
373 || (!c_prev.is_whitespace() && c_new.is_whitespace())
374 }
375 (UB::Backspace(Some(c_prev)), UB::Backspace(Some(c_new))) => {
376 (*c_new == '\n' || *c_new == '\r')
377 || (c_prev.is_whitespace() && !c_new.is_whitespace())
378 }
379 (UB::Backspace(_), UB::Backspace(_)) => false,
380 (UB::Delete(Some(c_prev)), UB::Delete(Some(c_new))) => {
381 (*c_new == '\n' || *c_new == '\r')
382 || (c_prev.is_whitespace() && !c_new.is_whitespace())
383 }
384 (UB::Delete(_), UB::Delete(_)) => false,
385 (_, _) => true,
386 }
387 }
388}
389
390#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, EnumIter)]
392pub enum ReedlineEvent {
393 None,
395
396 HistoryHintComplete,
398
399 HistoryHintWordComplete,
401
402 CtrlD,
409
410 CtrlC,
419
420 ClearScreen,
422
423 ClearScrollback,
427
428 Enter,
430
431 Submit,
433
434 SubmitOrNewline,
436
437 Esc,
439
440 Mouse, Resize(u16, u16),
445
446 Edit(Vec<EditCommand>),
448
449 Repaint,
451
452 PreviousHistory,
454
455 Up,
457
458 Down,
460
461 Right,
463
464 Left,
466
467 NextHistory,
469
470 SearchHistory,
472
473 Multiple(Vec<ReedlineEvent>),
476
477 UntilFound(Vec<ReedlineEvent>),
479
480 Menu(String),
482
483 MenuNext,
485
486 MenuPrevious,
488
489 MenuUp,
491
492 MenuDown,
494
495 MenuLeft,
497
498 MenuRight,
500
501 MenuPageNext,
503
504 MenuPagePrevious,
506
507 ExecuteHostCommand(String),
509
510 OpenEditor,
512}
513
514impl Display for ReedlineEvent {
515 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
516 match self {
517 ReedlineEvent::None => write!(f, "None"),
518 ReedlineEvent::HistoryHintComplete => write!(f, "HistoryHintComplete"),
519 ReedlineEvent::HistoryHintWordComplete => write!(f, "HistoryHintWordComplete"),
520 ReedlineEvent::CtrlD => write!(f, "CtrlD"),
521 ReedlineEvent::CtrlC => write!(f, "CtrlC"),
522 ReedlineEvent::ClearScreen => write!(f, "ClearScreen"),
523 ReedlineEvent::ClearScrollback => write!(f, "ClearScrollback"),
524 ReedlineEvent::Enter => write!(f, "Enter"),
525 ReedlineEvent::Submit => write!(f, "Submit"),
526 ReedlineEvent::SubmitOrNewline => write!(f, "SubmitOrNewline"),
527 ReedlineEvent::Esc => write!(f, "Esc"),
528 ReedlineEvent::Mouse => write!(f, "Mouse"),
529 ReedlineEvent::Resize(_, _) => write!(f, "Resize <int> <int>"),
530 ReedlineEvent::Edit(_) => write!(
531 f,
532 "Edit: <EditCommand> or Edit: <EditCommand> value: <string>"
533 ),
534 ReedlineEvent::Repaint => write!(f, "Repaint"),
535 ReedlineEvent::PreviousHistory => write!(f, "PreviousHistory"),
536 ReedlineEvent::Up => write!(f, "Up"),
537 ReedlineEvent::Down => write!(f, "Down"),
538 ReedlineEvent::Right => write!(f, "Right"),
539 ReedlineEvent::Left => write!(f, "Left"),
540 ReedlineEvent::NextHistory => write!(f, "NextHistory"),
541 ReedlineEvent::SearchHistory => write!(f, "SearchHistory"),
542 ReedlineEvent::Multiple(_) => write!(f, "Multiple[ {{ ReedLineEvents, }} ]"),
543 ReedlineEvent::UntilFound(_) => write!(f, "UntilFound [ {{ ReedLineEvents, }} ]"),
544 ReedlineEvent::Menu(_) => write!(f, "Menu Name: <string>"),
545 ReedlineEvent::MenuNext => write!(f, "MenuNext"),
546 ReedlineEvent::MenuPrevious => write!(f, "MenuPrevious"),
547 ReedlineEvent::MenuUp => write!(f, "MenuUp"),
548 ReedlineEvent::MenuDown => write!(f, "MenuDown"),
549 ReedlineEvent::MenuLeft => write!(f, "MenuLeft"),
550 ReedlineEvent::MenuRight => write!(f, "MenuRight"),
551 ReedlineEvent::MenuPageNext => write!(f, "MenuPageNext"),
552 ReedlineEvent::MenuPagePrevious => write!(f, "MenuPagePrevious"),
553 ReedlineEvent::ExecuteHostCommand(_) => write!(f, "ExecuteHostCommand"),
554 ReedlineEvent::OpenEditor => write!(f, "OpenEditor"),
555 }
556 }
557}
558
559pub(crate) enum EventStatus {
560 Handled,
561 Inapplicable,
562 Exits(Signal),
563}
564
565pub struct ReedlineRawEvent {
570 inner: Event,
571}
572
573impl ReedlineRawEvent {
574 pub fn convert_from(evt: Event) -> Option<Self> {
576 match evt {
577 Event::Key(KeyEvent {
578 kind: KeyEventKind::Release,
579 ..
580 }) => None,
581 Event::Key(KeyEvent {
582 code,
583 modifiers,
584 kind: KeyEventKind::Repeat,
585 state,
586 }) => Some(Self {
587 inner: Event::Key(KeyEvent {
588 code,
589 modifiers,
590 kind: KeyEventKind::Press,
591 state,
592 }),
593 }),
594 other => Some(Self { inner: other }),
595 }
596 }
597
598 pub fn into(self) -> Event {
600 self.inner
601 }
602}