1use display::DisplayColor;
2use input::{KeyCode, KeyEvent, KeyModifiers};
3use unicode_segmentation::UnicodeSegmentation;
4use view::LineSegment;
5
6use crate::events::Event;
7
8#[derive(Debug, PartialEq, Eq)]
9pub(crate) enum EditAction {
10 CursorMove,
11 ContentUpdate,
12 None,
13}
14
15pub(crate) struct EditableLine {
16 content: String,
17 cursor_position: usize,
18 label: Option<LineSegment>,
19 read_only: bool,
20}
21
22impl EditableLine {
23 pub(crate) const fn new() -> Self {
24 Self {
25 content: String::new(),
26 cursor_position: 0,
27 label: None,
28 read_only: false,
29 }
30 }
31
32 pub(crate) fn set_label(&mut self, label: LineSegment) {
33 self.label = Some(label);
34 }
35
36 pub(crate) fn set_content(&mut self, content: &str) {
37 self.content = String::from(content);
38 self.cursor_position = UnicodeSegmentation::graphemes(content, true).count();
39 }
40
41 pub(crate) fn set_read_only(&mut self, read_only: bool) {
42 self.read_only = read_only;
43 }
44
45 pub(crate) fn clear(&mut self) {
46 self.content.clear();
47 self.cursor_position = 0;
48 }
49
50 pub(crate) fn get_content(&self) -> &str {
51 self.content.as_str()
52 }
53
54 pub(crate) const fn cursor_position(&self) -> usize {
55 self.cursor_position
56 }
57
58 pub(crate) fn line_segments(&self) -> Vec<LineSegment> {
59 if self.read_only {
60 return vec![LineSegment::new(self.get_content())];
61 }
62
63 let line = self.content.as_str();
64 let pointer = self.cursor_position;
65
66 let graphemes = UnicodeSegmentation::graphemes(line, true);
67
68 let start = graphemes.clone().take(pointer).collect::<String>();
69 let indicator = graphemes.clone().skip(pointer).take(1).collect::<String>();
70 let end = graphemes.skip(pointer + 1).collect::<String>();
71
72 let mut segments = vec![];
73 if let Some(label) = self.label.as_ref() {
74 segments.push(label.clone());
75 }
76 if !start.is_empty() {
77 segments.push(LineSegment::new(start.as_str()));
78 }
79 segments.push(
80 if indicator.is_empty() {
81 LineSegment::new_with_color_and_style(" ", DisplayColor::Normal, false, true, false)
82 }
83 else {
84 LineSegment::new_with_color_and_style(indicator.as_str(), DisplayColor::Normal, false, true, false)
85 },
86 );
87 if !end.is_empty() {
88 segments.push(LineSegment::new(end.as_str()));
89 }
90
91 segments
92 }
93
94 pub(crate) fn handle_event(&mut self, event: Event) -> EditAction {
95 if self.read_only {
96 return EditAction::None;
97 }
98 match event {
99 Event::Key(KeyEvent {
100 code: KeyCode::Backspace,
101 modifiers: KeyModifiers::NONE,
102 }) => {
103 if self.cursor_position == 0 {
104 EditAction::None
105 }
106 else {
107 let start = UnicodeSegmentation::graphemes(self.content.as_str(), true)
108 .take(self.cursor_position - 1)
109 .collect::<String>();
110 let end = UnicodeSegmentation::graphemes(self.content.as_str(), true)
111 .skip(self.cursor_position)
112 .collect::<String>();
113 self.content = format!("{start}{end}");
114 self.cursor_position -= 1;
115 EditAction::ContentUpdate
116 }
117 },
118 Event::Key(KeyEvent {
119 code: KeyCode::Delete,
120 modifiers: KeyModifiers::NONE,
121 }) => {
122 let length = UnicodeSegmentation::graphemes(self.content.as_str(), true).count();
123 if self.cursor_position == length {
124 EditAction::None
125 }
126 else {
127 let start = UnicodeSegmentation::graphemes(self.content.as_str(), true)
128 .take(self.cursor_position)
129 .collect::<String>();
130 let end = UnicodeSegmentation::graphemes(self.content.as_str(), true)
131 .skip(self.cursor_position + 1)
132 .collect::<String>();
133 self.content = format!("{start}{end}");
134 EditAction::ContentUpdate
135 }
136 },
137 Event::Key(KeyEvent {
138 code: KeyCode::Home,
139 modifiers: KeyModifiers::NONE,
140 }) => {
141 if self.cursor_position == 0 {
142 EditAction::None
143 }
144 else {
145 self.cursor_position = 0;
146 EditAction::CursorMove
147 }
148 },
149 Event::Key(KeyEvent {
150 code: KeyCode::End,
151 modifiers: KeyModifiers::NONE,
152 }) => {
153 let new_position = UnicodeSegmentation::graphemes(self.content.as_str(), true).count();
154 if new_position == self.cursor_position {
155 EditAction::None
156 }
157 else {
158 self.cursor_position = new_position;
159 EditAction::CursorMove
160 }
161 },
162 Event::Key(KeyEvent {
163 code: KeyCode::Right,
164 modifiers: KeyModifiers::NONE,
165 }) => {
166 let length = UnicodeSegmentation::graphemes(self.content.as_str(), true).count();
167 if self.cursor_position < length {
168 self.cursor_position += 1;
169 EditAction::CursorMove
170 }
171 else {
172 EditAction::None
173 }
174 },
175 Event::Key(KeyEvent {
176 code: KeyCode::Left,
177 modifiers: KeyModifiers::NONE,
178 }) => {
179 if self.cursor_position == 0 {
180 EditAction::None
181 }
182 else {
183 self.cursor_position -= 1;
184 EditAction::CursorMove
185 }
186 },
187 Event::Key(KeyEvent {
188 code: KeyCode::Char(c),
189 modifiers: KeyModifiers::NONE,
190 }) => {
191 let start = UnicodeSegmentation::graphemes(self.content.as_str(), true)
192 .take(self.cursor_position)
193 .collect::<String>();
194 let end = UnicodeSegmentation::graphemes(self.content.as_str(), true)
195 .skip(self.cursor_position)
196 .collect::<String>();
197 self.content = format!("{start}{c}{end}");
198 self.cursor_position += 1;
199 EditAction::ContentUpdate
200 },
201 _ => EditAction::None,
202 }
203 }
204}
205
206#[cfg(test)]
207mod tests {
208 use view::{assert_rendered_output, ViewData, ViewLine};
209
210 use super::*;
211
212 macro_rules! view_data_from_editable_line {
213 ($editable_line:expr) => {{
214 let segments = $editable_line.line_segments();
215 &ViewData::new(|updater| updater.push_line(ViewLine::from(segments)))
216 }};
217 }
218
219 fn handle_events(module: &mut EditableLine, events: &[Event]) {
220 for event in events {
221 _ = module.handle_event(*event);
222 }
223 }
224
225 #[test]
226 fn with_label() {
227 let mut editable_line = EditableLine::new();
228 editable_line.set_content("foobar");
229 editable_line.set_label(LineSegment::new("Label: "));
230 assert_rendered_output!(
231 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
232 view_data_from_editable_line!(&editable_line),
233 "{BODY}",
234 "{Normal}Label: foobar{Normal,Underline} "
235 );
236 }
237
238 #[test]
239 fn move_cursor_end() {
240 let mut editable_line = EditableLine::new();
241 editable_line.set_content("foobar");
242 _ = editable_line.handle_event(Event::from(KeyCode::Right));
243 assert_rendered_output!(
244 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
245 view_data_from_editable_line!(&editable_line),
246 "{BODY}",
247 "{Normal}foobar{Normal,Underline} "
248 );
249 }
250
251 #[test]
252 fn move_cursor_1_left() {
253 let mut editable_line = EditableLine::new();
254 editable_line.set_content("foobar");
255 _ = editable_line.handle_event(Event::from(KeyCode::Left));
256 assert_rendered_output!(
257 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
258 view_data_from_editable_line!(&editable_line),
259 "{BODY}",
260 "{Normal}fooba{Normal,Underline}r"
261 );
262 }
263
264 #[test]
265 fn move_cursor_2_from_start() {
266 let mut editable_line = EditableLine::new();
267 editable_line.set_content("foobar");
268 handle_events(&mut editable_line, &[Event::from(KeyCode::Left); 2]);
269 assert_rendered_output!(
270 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
271 view_data_from_editable_line!(&editable_line),
272 "{BODY}",
273 "{Normal}foob{Normal,Underline}a{Normal}r"
274 );
275 }
276
277 #[test]
278 fn move_cursor_1_from_start() {
279 let mut editable_line = EditableLine::new();
280 editable_line.set_content("foobar");
281 handle_events(&mut editable_line, &[Event::from(KeyCode::Left); 5]);
282 assert_rendered_output!(
283 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
284 view_data_from_editable_line!(&editable_line),
285 "{BODY}",
286 "{Normal}f{Normal,Underline}o{Normal}obar"
287 );
288 }
289
290 #[test]
291 fn move_cursor_to_start() {
292 let mut editable_line = EditableLine::new();
293 editable_line.set_content("foobar");
294 handle_events(&mut editable_line, &[Event::from(KeyCode::Left); 6]);
295 assert_rendered_output!(
296 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
297 view_data_from_editable_line!(&editable_line),
298 "{BODY}",
299 "{Normal,Underline}f{Normal}oobar"
300 );
301 }
302
303 #[test]
304 fn move_cursor_to_home() {
305 let mut editable_line = EditableLine::new();
306 editable_line.set_content("foobar");
307 _ = editable_line.handle_event(Event::from(KeyCode::Home));
308 assert_rendered_output!(
309 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
310 view_data_from_editable_line!(&editable_line),
311 "{BODY}",
312 "{Normal,Underline}f{Normal}oobar"
313 );
314 }
315
316 #[test]
317 fn move_cursor_right() {
318 let mut editable_line = EditableLine::new();
319 editable_line.set_content("foobar");
320 handle_events(&mut editable_line, &[
321 Event::from(KeyCode::Left),
322 Event::from(KeyCode::Left),
323 Event::from(KeyCode::Left),
324 Event::from(KeyCode::Right),
325 ]);
326 assert_rendered_output!(
327 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
328 view_data_from_editable_line!(&editable_line),
329 "{BODY}",
330 "{Normal}foob{Normal,Underline}a{Normal}r"
331 );
332 }
333
334 #[test]
335 fn move_cursor_to_end() {
336 let mut editable_line = EditableLine::new();
337 editable_line.set_content("foobar");
338 handle_events(&mut editable_line, &[
339 Event::from(KeyCode::Left),
340 Event::from(KeyCode::Left),
341 Event::from(KeyCode::Left),
342 Event::from(KeyCode::End),
343 ]);
344 assert_rendered_output!(
345 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
346 view_data_from_editable_line!(&editable_line),
347 "{BODY}",
348 "{Normal}foobar{Normal,Underline} "
349 );
350 }
351
352 #[test]
353 fn move_cursor_on_empty_content() {
354 let mut editable_line = EditableLine::new();
355 handle_events(&mut editable_line, &[
356 Event::from(KeyCode::Left),
357 Event::from(KeyCode::Right),
358 Event::from(KeyCode::End),
359 Event::from(KeyCode::Home),
360 ]);
361 assert_rendered_output!(
362 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
363 view_data_from_editable_line!(&editable_line),
364 "{BODY}",
365 "{Normal,Underline} "
366 );
367 }
368
369 #[test]
370 fn move_cursor_attempt_past_start() {
371 let mut editable_line = EditableLine::new();
372 editable_line.set_content("foobar");
373 handle_events(&mut editable_line, &[Event::from(KeyCode::Left); 10]);
374 assert_rendered_output!(
375 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
376 view_data_from_editable_line!(&editable_line),
377 "{BODY}",
378 "{Normal,Underline}f{Normal}oobar"
379 );
380 }
381
382 #[test]
383 fn move_cursor_attempt_past_end() {
384 let mut editable_line = EditableLine::new();
385 editable_line.set_content("foobar");
386 handle_events(&mut editable_line, &[Event::from(KeyCode::Right); 10]);
387 assert_rendered_output!(
388 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
389 view_data_from_editable_line!(&editable_line),
390 "{BODY}",
391 "{Normal}foobar{Normal,Underline} "
392 );
393 }
394
395 #[test]
396 fn multiple_width_unicode_single_width() {
397 let mut editable_line = EditableLine::new();
398 editable_line.set_content("a🗳b");
399 handle_events(&mut editable_line, &[Event::from(KeyCode::Left); 2]);
400 assert_rendered_output!(
401 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
402 view_data_from_editable_line!(&editable_line),
403 "{BODY}",
404 "{Normal}a{Normal,Underline}🗳{Normal}b"
405 );
406 }
407
408 #[test]
409 fn multiple_width_unicode_emoji() {
410 let mut editable_line = EditableLine::new();
411 editable_line.set_content("a😀b");
412 handle_events(&mut editable_line, &[Event::from(KeyCode::Left); 2]);
413 assert_rendered_output!(
414 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
415 view_data_from_editable_line!(&editable_line),
416 "{BODY}",
417 "{Normal}a{Normal,Underline}😀{Normal}b"
418 );
419 }
420
421 #[test]
422 fn add_character_end() {
423 let mut editable_line = EditableLine::new();
424 editable_line.set_content("abcd");
425 _ = editable_line.handle_event(Event::from('x'));
426 assert_rendered_output!(
427 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
428 view_data_from_editable_line!(&editable_line),
429 "{BODY}",
430 "{Normal}abcdx{Normal,Underline} "
431 );
432 }
433
434 #[test]
435 fn add_character_one_from_end() {
436 let mut editable_line = EditableLine::new();
437 editable_line.set_content("abcd");
438 handle_events(&mut editable_line, &[Event::from(KeyCode::Left), Event::from('x')]);
439 assert_rendered_output!(
440 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
441 view_data_from_editable_line!(&editable_line),
442 "{BODY}",
443 "{Normal}abcx{Normal,Underline}d"
444 );
445 }
446
447 #[test]
448 fn add_character_one_from_start() {
449 let mut editable_line = EditableLine::new();
450 editable_line.set_content("abcd");
451 handle_events(&mut editable_line, &[
452 Event::from(KeyCode::Left),
453 Event::from(KeyCode::Left),
454 Event::from(KeyCode::Left),
455 Event::from('x'),
456 ]);
457 assert_rendered_output!(
458 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
459 view_data_from_editable_line!(&editable_line),
460 "{BODY}",
461 "{Normal}ax{Normal,Underline}b{Normal}cd"
462 );
463 }
464
465 #[test]
466 fn add_character_at_start() {
467 let mut editable_line = EditableLine::new();
468 editable_line.set_content("abcd");
469 handle_events(&mut editable_line, &[
470 Event::from(KeyCode::Left),
471 Event::from(KeyCode::Left),
472 Event::from(KeyCode::Left),
473 Event::from(KeyCode::Left),
474 Event::from('x'),
475 ]);
476 assert_rendered_output!(
477 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
478 view_data_from_editable_line!(&editable_line),
479 "{BODY}",
480 "{Normal}x{Normal,Underline}a{Normal}bcd"
481 );
482 }
483
484 #[test]
485 fn add_character_uppercase() {
486 let mut editable_line = EditableLine::new();
487 editable_line.set_content("abcd");
488 _ = editable_line.handle_event(Event::from(KeyCode::Char('X')));
489 assert_rendered_output!(
490 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
491 view_data_from_editable_line!(&editable_line),
492 "{BODY}",
493 "{Normal}abcdX{Normal,Underline} "
494 );
495 }
496
497 #[test]
498 fn backspace_at_end() {
499 let mut editable_line = EditableLine::new();
500 editable_line.set_content("abcd");
501 _ = editable_line.handle_event(Event::from(KeyCode::Backspace));
502 assert_rendered_output!(
503 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
504 view_data_from_editable_line!(&editable_line),
505 "{BODY}",
506 "{Normal}abc{Normal,Underline} "
507 );
508 }
509
510 #[test]
511 fn backspace_one_from_end() {
512 let mut editable_line = EditableLine::new();
513 editable_line.set_content("abcd");
514 handle_events(&mut editable_line, &[
515 Event::from(KeyCode::Left),
516 Event::from(KeyCode::Backspace),
517 ]);
518 assert_rendered_output!(
519 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
520 view_data_from_editable_line!(&editable_line),
521 "{BODY}",
522 "{Normal}ab{Normal,Underline}d"
523 );
524 }
525
526 #[test]
527 fn backspace_one_from_start() {
528 let mut editable_line = EditableLine::new();
529 editable_line.set_content("abcd");
530 handle_events(&mut editable_line, &[
531 Event::from(KeyCode::Left),
532 Event::from(KeyCode::Left),
533 Event::from(KeyCode::Left),
534 Event::from(KeyCode::Backspace),
535 ]);
536 assert_rendered_output!(
537 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
538 view_data_from_editable_line!(&editable_line),
539 "{BODY}",
540 "{Normal,Underline}b{Normal}cd"
541 );
542 }
543
544 #[test]
545 fn backspace_at_start() {
546 let mut editable_line = EditableLine::new();
547 editable_line.set_content("abcd");
548 handle_events(&mut editable_line, &[
549 Event::from(KeyCode::Left),
550 Event::from(KeyCode::Left),
551 Event::from(KeyCode::Left),
552 Event::from(KeyCode::Left),
553 Event::from(KeyCode::Backspace),
554 ]);
555 assert_rendered_output!(
556 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
557 view_data_from_editable_line!(&editable_line),
558 "{BODY}",
559 "{Normal,Underline}a{Normal}bcd"
560 );
561 }
562
563 #[test]
564 fn delete_at_end() {
565 let mut editable_line = EditableLine::new();
566 editable_line.set_content("abcd");
567 _ = editable_line.handle_event(Event::from(KeyCode::Delete));
568 assert_rendered_output!(
569 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
570 view_data_from_editable_line!(&editable_line),
571 "{BODY}",
572 "{Normal}abcd{Normal,Underline} "
573 );
574 }
575
576 #[test]
577 fn delete_last_character() {
578 let mut editable_line = EditableLine::new();
579 editable_line.set_content("abcd");
580 handle_events(&mut editable_line, &[
581 Event::from(KeyCode::Left),
582 Event::from(KeyCode::Delete),
583 ]);
584 assert_rendered_output!(
585 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
586 view_data_from_editable_line!(&editable_line),
587 "{BODY}",
588 "{Normal}abc{Normal,Underline} "
589 );
590 }
591
592 #[test]
593 fn delete_second_character() {
594 let mut editable_line = EditableLine::new();
595 editable_line.set_content("abcd");
596 handle_events(&mut editable_line, &[
597 Event::from(KeyCode::Left),
598 Event::from(KeyCode::Left),
599 Event::from(KeyCode::Left),
600 Event::from(KeyCode::Delete),
601 ]);
602 assert_rendered_output!(
603 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
604 view_data_from_editable_line!(&editable_line),
605 "{BODY}",
606 "{Normal}a{Normal,Underline}c{Normal}d"
607 );
608 }
609
610 #[test]
611 fn delete_first_character() {
612 let mut editable_line = EditableLine::new();
613 editable_line.set_content("abcd");
614 handle_events(&mut editable_line, &[
615 Event::from(KeyCode::Left),
616 Event::from(KeyCode::Left),
617 Event::from(KeyCode::Left),
618 Event::from(KeyCode::Left),
619 Event::from(KeyCode::Delete),
620 ]);
621 assert_rendered_output!(
622 Options AssertRenderOptions::INCLUDE_TRAILING_WHITESPACE,
623 view_data_from_editable_line!(&editable_line),
624 "{BODY}",
625 "{Normal,Underline}b{Normal}cd"
626 );
627 }
628
629 #[test]
630 fn ignore_other_input() {
631 let mut editable_line = EditableLine::new();
632 _ = editable_line.handle_event(Event::from(KeyCode::Null));
633 }
634
635 #[test]
636 fn ignore_input_on_readonly() {
637 let mut editable_line = EditableLine::new();
638 editable_line.set_content("abcd");
639 editable_line.set_read_only(true);
640 _ = editable_line.handle_event(Event::from(KeyCode::Home));
641 assert_eq!(editable_line.cursor_position(), 4);
642 }
643
644 #[test]
645 fn set_get_content() {
646 let mut editable_line = EditableLine::new();
647 editable_line.set_content("abcd");
648 assert_eq!(editable_line.cursor_position(), 4);
649 assert_eq!(editable_line.get_content(), "abcd");
650 }
651
652 #[test]
653 fn set_readonly() {
654 let mut editable_line = EditableLine::new();
655 editable_line.set_content("abcd");
656 editable_line.set_read_only(true);
657 assert_eq!(editable_line.line_segments().len(), 1);
658 }
659
660 #[test]
661 fn clear_content() {
662 let mut editable_line = EditableLine::new();
663 editable_line.set_content("abcd");
664 editable_line.clear();
665 assert_eq!(editable_line.cursor_position(), 0);
666 assert_eq!(editable_line.get_content(), "");
667 }
668
669 #[test]
670 fn handle_event_edit_action_backspace_with_content() {
671 let mut editable_line = EditableLine::new();
672 editable_line.set_content("abcd");
673 assert_eq!(
674 editable_line.handle_event(Event::from(KeyCode::Backspace)),
675 EditAction::ContentUpdate
676 );
677 }
678
679 #[test]
680 fn handle_event_edit_action_backspace_without_content() {
681 let mut editable_line = EditableLine::new();
682 editable_line.set_content("");
683 assert_eq!(
684 editable_line.handle_event(Event::from(KeyCode::Backspace)),
685 EditAction::None
686 );
687 }
688
689 #[test]
690 fn handle_event_edit_action_delete_with_content() {
691 let mut editable_line = EditableLine::new();
692 editable_line.set_content("abcd");
693 editable_line.cursor_position = 0;
694 assert_eq!(
695 editable_line.handle_event(Event::from(KeyCode::Delete)),
696 EditAction::ContentUpdate
697 );
698 }
699
700 #[test]
701 fn handle_event_edit_action_delete_without_content() {
702 let mut editable_line = EditableLine::new();
703 editable_line.set_content("");
704 assert_eq!(
705 editable_line.handle_event(Event::from(KeyCode::Delete)),
706 EditAction::None
707 );
708 }
709
710 #[test]
711 fn handle_event_edit_action_home_with_cursor_change() {
712 let mut editable_line = EditableLine::new();
713 editable_line.set_content("abcd");
714 assert_eq!(
715 editable_line.handle_event(Event::from(KeyCode::Home)),
716 EditAction::CursorMove
717 );
718 }
719
720 #[test]
721 fn handle_event_edit_action_home_without_cursor_change() {
722 let mut editable_line = EditableLine::new();
723 editable_line.set_content("abcd");
724 editable_line.cursor_position = 0;
725 assert_eq!(editable_line.handle_event(Event::from(KeyCode::Home)), EditAction::None);
726 }
727
728 #[test]
729 fn handle_event_edit_action_end_with_cursor_change() {
730 let mut editable_line = EditableLine::new();
731 editable_line.set_content("abcd");
732 editable_line.cursor_position = 0;
733 assert_eq!(
734 editable_line.handle_event(Event::from(KeyCode::End)),
735 EditAction::CursorMove
736 );
737 }
738
739 #[test]
740 fn handle_event_edit_action_end_without_cursor_change() {
741 let mut editable_line = EditableLine::new();
742 editable_line.set_content("abcd");
743 assert_eq!(editable_line.handle_event(Event::from(KeyCode::End)), EditAction::None);
744 }
745
746 #[test]
747 fn handle_event_edit_action_right_with_cursor_change() {
748 let mut editable_line = EditableLine::new();
749 editable_line.set_content("abcd");
750 editable_line.cursor_position = 0;
751 assert_eq!(
752 editable_line.handle_event(Event::from(KeyCode::Right)),
753 EditAction::CursorMove
754 );
755 }
756
757 #[test]
758 fn handle_event_edit_action_right_without_cursor_change() {
759 let mut editable_line = EditableLine::new();
760 editable_line.set_content("abcd");
761 assert_eq!(
762 editable_line.handle_event(Event::from(KeyCode::Right)),
763 EditAction::None
764 );
765 }
766
767 #[test]
768 fn handle_event_edit_action_left_with_cursor_change() {
769 let mut editable_line = EditableLine::new();
770 editable_line.set_content("abcd");
771 assert_eq!(
772 editable_line.handle_event(Event::from(KeyCode::Left)),
773 EditAction::CursorMove
774 );
775 }
776
777 #[test]
778 fn handle_event_edit_action_left_without_cursor_change() {
779 let mut editable_line = EditableLine::new();
780 editable_line.set_content("abcd");
781 editable_line.cursor_position = 0;
782 assert_eq!(editable_line.handle_event(Event::from(KeyCode::Left)), EditAction::None);
783 }
784
785 #[test]
786 fn handle_event_edit_action_new_character() {
787 let mut editable_line = EditableLine::new();
788 editable_line.set_content("abcd");
789 assert_eq!(
790 editable_line.handle_event(Event::from(KeyCode::Char('a'))),
791 EditAction::ContentUpdate
792 );
793 }
794
795 #[test]
796 fn handle_event_edit_action_other() {
797 let mut editable_line = EditableLine::new();
798 editable_line.set_content("abcd");
799 assert_eq!(editable_line.handle_event(Event::from(KeyCode::Esc)), EditAction::None);
800 }
801}