1use std::{
2 fmt,
3 io::{self, Write},
4};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum Color {
11 Black,
12 Red,
13 Green,
14 Yellow,
15 Blue,
16 Magenta,
17 Cyan,
18 White,
19 BrightBlack,
20 BrightRed,
21 BrightGreen,
22 BrightYellow,
23 BrightBlue,
24 BrightMagenta,
25 BrightCyan,
26 BrightWhite,
27 Indexed(u8),
29 Rgb(u8, u8, u8),
31 Reset,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
37pub enum Attribute {
38 Bold,
39 Dim,
40 Italic,
41 Underline,
42 SlowBlink,
43 RapidBlink,
44 Reverse,
45 Hidden,
46 Strikethrough,
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51pub enum ClearType {
52 All,
53 FromCursorDown,
54 FromCursorUp,
55 CurrentLine,
56 UntilNewLine,
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub enum MouseButton {
62 Left,
63 Right,
64 Middle,
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
69pub enum MouseEventKind {
70 Down(MouseButton),
71 Up(MouseButton),
72 Drag(MouseButton),
73 Move,
74 ScrollUp,
75 ScrollDown,
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub struct MouseEvent {
81 pub kind: MouseEventKind,
82 pub column: u16,
83 pub row: u16,
84 pub modifiers: Modifiers,
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
89pub struct Modifiers {
90 pub shift: bool,
91 pub control: bool,
92 pub alt: bool,
93 pub meta: bool,
94}
95
96#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
98pub enum KeyCode {
99 Char(char),
100 Enter,
101 Esc,
102 Backspace,
103 Tab,
104 Space,
105 Left,
106 Right,
107 Up,
108 Down,
109 Home,
110 End,
111 PageUp,
112 PageDown,
113 Delete,
114 Insert,
115 F(u8),
116 Null,
117 CapsLock,
118 ScrollLock,
119 NumLock,
120 PrintScreen,
121 Pause,
122 Menu,
123 KeypadBegin,
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq)]
128pub struct KeyEvent {
129 pub code: KeyCode,
130 pub modifiers: Modifiers,
131}
132
133#[derive(Debug, Clone)]
137pub enum OutputCommand {
138 MoveTo(u16, u16),
141 MoveUp(u16),
143 MoveDown(u16),
145 MoveLeft(u16),
147 MoveRight(u16),
149 MoveToNextLine(u16),
151 MoveToPreviousLine(u16),
153 MoveToColumn(u16),
155 SavePosition,
157 RestorePosition,
159 GetPosition,
161 Hide,
163 Show,
165 EnableBlinking,
167 DisableBlinking,
169 SetCursorStyle(CursorStyle),
171
172 Print(String),
175 PrintLine(String),
177 PrintStyled(StyledText),
179
180 SetForegroundColor(Color),
183 SetBackgroundColor(Color),
185 ResetColor,
187 SetColors(Color, Color),
189 SetAttribute(Attribute),
191 ResetAttributes,
193 SetLineWrap(bool),
195
196 Clear(ClearType),
199 ScrollUp(u16),
201 ScrollDown(u16),
202 SetSize(u16, u16),
204 GetSize,
206 EnterAlternateScreen,
208 LeaveAlternateScreen,
210 SetTitle(String),
212 EnableMouseCapture,
214 DisableMouseCapture,
216 EnableFocusReporting,
218 DisableFocusReporting,
220
221 PushKeyboardEvent(KeyEvent),
224 PushMouseEvent(MouseEvent),
226
227 Batch(Vec<OutputCommand>),
230 If(bool, Box<OutputCommand>, Option<Box<OutputCommand>>),
232 Repeat(u32, Box<OutputCommand>),
234}
235
236#[derive(Debug, Clone, Copy, PartialEq, Eq)]
238pub enum CursorStyle {
239 Default,
240 BlinkingBlock,
241 SteadyBlock,
242 BlinkingUnderline,
243 SteadyUnderline,
244 BlinkingBar,
245 SteadyBar,
246}
247
248#[derive(Debug, Clone)]
250pub struct StyledText {
251 pub text: String,
252 pub foreground: Option<Color>,
253 pub background: Option<Color>,
254 pub attributes: Vec<Attribute>,
255}
256
257impl OutputCommand {
260 pub fn execute(&self, writer: &mut dyn Write) -> io::Result<()> {
262 self.write_ansi(writer, true)
263 }
264
265 pub fn queue(&self, writer: &mut dyn Write) -> io::Result<()> {
267 self.write_ansi(writer, false)
268 }
269
270 fn write_ansi(&self, writer: &mut dyn Write, flush: bool) -> io::Result<()> {
272 match self {
273 OutputCommand::MoveTo(col, row) => {
275 write!(writer, "\x1b[{};{}H", row, col)?;
277 }
278 OutputCommand::MoveUp(n) => {
279 if *n > 0 {
281 write!(writer, "\x1b[{}A", n)?;
282 }
283 }
284 OutputCommand::MoveDown(n) => {
285 if *n > 0 {
287 write!(writer, "\x1b[{}B", n)?;
288 }
289 }
290 OutputCommand::MoveLeft(n) => {
291 if *n > 0 {
293 write!(writer, "\x1b[{}D", n)?;
294 }
295 }
296 OutputCommand::MoveRight(n) => {
297 if *n > 0 {
299 write!(writer, "\x1b[{}C", n)?;
300 }
301 }
302 OutputCommand::MoveToNextLine(n) => {
303 if *n > 0 {
305 write!(writer, "\x1b[{}E", n)?;
306 }
307 }
308 OutputCommand::MoveToPreviousLine(n) => {
309 if *n > 0 {
311 write!(writer, "\x1b[{}F", n)?;
312 }
313 }
314 OutputCommand::MoveToColumn(col) => {
315 write!(writer, "\x1b[{}G", col)?;
317 }
318 OutputCommand::SavePosition => {
319 write!(writer, "\x1b7")?;
321 }
322 OutputCommand::RestorePosition => {
323 write!(writer, "\x1b8")?;
325 }
326 OutputCommand::GetPosition => {
327 write!(writer, "\x1b[6n")?;
329 }
330 OutputCommand::Hide => {
331 write!(writer, "\x1b[?25l")?;
333 }
334 OutputCommand::Show => {
335 write!(writer, "\x1b[?25h")?;
337 }
338 OutputCommand::EnableBlinking => {
339 write!(writer, "\x1b[?12h")?;
341 }
342 OutputCommand::DisableBlinking => {
343 write!(writer, "\x1b[?12l")?;
345 }
346 OutputCommand::SetCursorStyle(style) => {
347 let ps = match style {
349 CursorStyle::Default => 0,
350 CursorStyle::BlinkingBlock => 1,
351 CursorStyle::SteadyBlock => 2,
352 CursorStyle::BlinkingUnderline => 3,
353 CursorStyle::SteadyUnderline => 4,
354 CursorStyle::BlinkingBar => 5,
355 CursorStyle::SteadyBar => 6,
356 };
357 write!(writer, "\x1b[{} q", ps)?;
358 }
359
360 OutputCommand::Print(text) => {
362 write!(writer, "{}", text)?;
363 }
364 OutputCommand::PrintLine(text) => {
365 write!(writer, "{}\r\n", text)?;
366 }
367 OutputCommand::PrintStyled(styled) => {
368 if let Some(fg) = &styled.foreground {
370 Self::write_color(writer, fg, true)?;
371 }
372 if let Some(bg) = &styled.background {
373 Self::write_color(writer, bg, false)?;
374 }
375 for attr in &styled.attributes {
376 Self::write_attribute(writer, *attr, true)?;
377 }
378
379 write!(writer, "{}", styled.text)?;
381
382 if !styled.attributes.is_empty() {
384 write!(writer, "\x1b[0m")?;
385 }
386 }
387
388 OutputCommand::SetForegroundColor(color) => {
390 Self::write_color(writer, color, true)?;
391 }
392 OutputCommand::SetBackgroundColor(color) => {
393 Self::write_color(writer, color, false)?;
394 }
395 OutputCommand::ResetColor => {
396 write!(writer, "\x1b[39;49m")?;
398 }
399 OutputCommand::SetColors(fg, bg) => {
400 Self::write_color(writer, fg, true)?;
401 Self::write_color(writer, bg, false)?;
402 }
403 OutputCommand::SetAttribute(attr) => {
404 Self::write_attribute(writer, *attr, true)?;
405 }
406 OutputCommand::ResetAttributes => {
407 write!(writer, "\x1b[0m")?;
409 }
410 OutputCommand::SetLineWrap(enable) => {
411 if *enable {
412 write!(writer, "\x1b[?7h")?;
414 } else {
415 write!(writer, "\x1b[?7l")?;
417 }
418 }
419
420 OutputCommand::Clear(clear_type) => {
422 match clear_type {
423 ClearType::All => {
424 write!(writer, "\x1b[2J")?;
426 }
427 ClearType::FromCursorDown => {
428 write!(writer, "\x1b[0J")?;
430 }
431 ClearType::FromCursorUp => {
432 write!(writer, "\x1b[1J")?;
434 }
435 ClearType::CurrentLine => {
436 write!(writer, "\x1b[2K")?;
438 }
439 ClearType::UntilNewLine => {
440 write!(writer, "\x1b[0K")?;
442 }
443 }
444 }
445 OutputCommand::ScrollUp(lines) => {
446 if *lines > 0 {
448 write!(writer, "\x1b[{}S", lines)?;
449 }
450 }
451 OutputCommand::ScrollDown(lines) => {
452 if *lines > 0 {
454 write!(writer, "\x1b[{}T", lines)?;
455 }
456 }
457 OutputCommand::SetSize(cols, rows) => {
458 write!(writer, "\x1b[8;{};{}t", rows, cols)?;
461 }
462 OutputCommand::GetSize => {
463 write!(writer, "\x1b[18t")?;
465 }
466 OutputCommand::EnterAlternateScreen => {
467 write!(writer, "\x1b[?1049h")?;
469 }
470 OutputCommand::LeaveAlternateScreen => {
471 write!(writer, "\x1b[?1049l")?;
473 }
474 OutputCommand::SetTitle(title) => {
475 write!(writer, "\x1b]0;{}\x07", title)?;
477 }
478 OutputCommand::EnableMouseCapture => {
479 write!(writer, "\x1b[?1000h")?;
481 write!(writer, "\x1b[?1002h")?;
483 write!(writer, "\x1b[?1006h")?;
485 }
486 OutputCommand::DisableMouseCapture => {
487 write!(writer, "\x1b[?1006l")?;
489 write!(writer, "\x1b[?1002l")?;
491 write!(writer, "\x1b[?1000l")?;
493 }
494 OutputCommand::EnableFocusReporting => {
495 write!(writer, "\x1b[?1004h")?;
497 }
498 OutputCommand::DisableFocusReporting => {
499 write!(writer, "\x1b[?1004l")?;
501 }
502
503 OutputCommand::PushKeyboardEvent(event) => {
505 let _ = event;
509 }
510 OutputCommand::PushMouseEvent(event) => {
511 let _ = event;
513 }
514
515 OutputCommand::Batch(commands) => {
517 for cmd in commands {
518 cmd.write_ansi(writer, false)?;
519 }
520 }
521 OutputCommand::If(condition, then_cmd, else_cmd) => {
522 if *condition {
523 then_cmd.write_ansi(writer, false)?;
524 } else if let Some(else_cmd) = else_cmd {
525 else_cmd.write_ansi(writer, false)?;
526 }
527 }
528 OutputCommand::Repeat(count, cmd) => {
529 for _ in 0..*count {
530 cmd.write_ansi(writer, false)?;
531 }
532 }
533 }
534
535 if flush {
536 writer.flush()?;
537 }
538
539 Ok(())
540 }
541
542 fn write_color(writer: &mut dyn Write, color: &Color, is_foreground: bool) -> io::Result<()> {
544 let code = match color {
545 Color::Black => {
546 if is_foreground {
547 30
548 } else {
549 40
550 }
551 }
552 Color::Red => {
553 if is_foreground {
554 31
555 } else {
556 41
557 }
558 }
559 Color::Green => {
560 if is_foreground {
561 32
562 } else {
563 42
564 }
565 }
566 Color::Yellow => {
567 if is_foreground {
568 33
569 } else {
570 43
571 }
572 }
573 Color::Blue => {
574 if is_foreground {
575 34
576 } else {
577 44
578 }
579 }
580 Color::Magenta => {
581 if is_foreground {
582 35
583 } else {
584 45
585 }
586 }
587 Color::Cyan => {
588 if is_foreground {
589 36
590 } else {
591 46
592 }
593 }
594 Color::White => {
595 if is_foreground {
596 37
597 } else {
598 47
599 }
600 }
601 Color::BrightBlack => {
602 if is_foreground {
603 90
604 } else {
605 100
606 }
607 }
608 Color::BrightRed => {
609 if is_foreground {
610 91
611 } else {
612 101
613 }
614 }
615 Color::BrightGreen => {
616 if is_foreground {
617 92
618 } else {
619 102
620 }
621 }
622 Color::BrightYellow => {
623 if is_foreground {
624 93
625 } else {
626 103
627 }
628 }
629 Color::BrightBlue => {
630 if is_foreground {
631 94
632 } else {
633 104
634 }
635 }
636 Color::BrightMagenta => {
637 if is_foreground {
638 95
639 } else {
640 105
641 }
642 }
643 Color::BrightCyan => {
644 if is_foreground {
645 96
646 } else {
647 106
648 }
649 }
650 Color::BrightWhite => {
651 if is_foreground {
652 97
653 } else {
654 107
655 }
656 }
657 Color::Indexed(n) => {
658 if is_foreground {
659 write!(writer, "\x1b[38;5;{}m", n)?;
660 return Ok(());
661 } else {
662 write!(writer, "\x1b[48;5;{}m", n)?;
663 return Ok(());
664 }
665 }
666 Color::Rgb(r, g, b) => {
667 if is_foreground {
668 write!(writer, "\x1b[38;2;{};{};{}m", r, g, b)?;
669 return Ok(());
670 } else {
671 write!(writer, "\x1b[48;2;{};{};{}m", r, g, b)?;
672 return Ok(());
673 }
674 }
675 Color::Reset => {
676 if is_foreground {
677 write!(writer, "\x1b[39m")?;
678 } else {
679 write!(writer, "\x1b[49m")?;
680 }
681 return Ok(());
682 }
683 };
684
685 write!(writer, "\x1b[{}m", code)
686 }
687
688 fn write_attribute(writer: &mut dyn Write, attr: Attribute, enable: bool) -> io::Result<()> {
690 let code = match attr {
691 Attribute::Bold => {
692 if enable {
693 1
694 } else {
695 22
696 }
697 }
698 Attribute::Dim => {
699 if enable {
700 2
701 } else {
702 22
703 }
704 }
705 Attribute::Italic => {
706 if enable {
707 3
708 } else {
709 23
710 }
711 }
712 Attribute::Underline => {
713 if enable {
714 4
715 } else {
716 24
717 }
718 }
719 Attribute::SlowBlink => {
720 if enable {
721 5
722 } else {
723 25
724 }
725 }
726 Attribute::RapidBlink => {
727 if enable {
728 6
729 } else {
730 25
731 }
732 }
733 Attribute::Reverse => {
734 if enable {
735 7
736 } else {
737 27
738 }
739 }
740 Attribute::Hidden => {
741 if enable {
742 8
743 } else {
744 28
745 }
746 }
747 Attribute::Strikethrough => {
748 if enable {
749 9
750 } else {
751 29
752 }
753 }
754 };
755
756 write!(writer, "\x1b[{}m", code)
757 }
758
759 pub fn print<S: Into<String>>(text: S) -> Self {
763 OutputCommand::Print(text.into())
764 }
765
766 pub fn print_line<S: Into<String>>(text: S) -> Self {
768 OutputCommand::PrintLine(text.into())
769 }
770
771 pub fn move_to(col: u16, row: u16) -> Self {
773 OutputCommand::MoveTo(col, row)
774 }
775
776 pub fn clear(clear_type: ClearType) -> Self {
778 OutputCommand::Clear(clear_type)
779 }
780
781 pub fn set_colors(foreground: Color, background: Color) -> Self {
783 OutputCommand::SetColors(foreground, background)
784 }
785
786 pub fn batch<I>(commands: I) -> Self
788 where
789 I: IntoIterator<Item = OutputCommand>,
790 {
791 OutputCommand::Batch(commands.into_iter().collect())
792 }
793
794 pub fn if_then_else<C, T, E>(condition: bool, then_cmd: C, else_cmd: Option<E>) -> Self
796 where
797 C: Into<OutputCommand>,
798 E: Into<OutputCommand>,
799 {
800 let then_box = Box::new(then_cmd.into());
801 let else_box = else_cmd.map(|cmd| Box::new(cmd.into()));
802 OutputCommand::If(condition, then_box, else_box)
803 }
804
805 pub fn repeat<C>(count: u32, cmd: C) -> Self
807 where
808 C: Into<OutputCommand>,
809 {
810 OutputCommand::Repeat(count, Box::new(cmd.into()))
811 }
812
813 pub fn styled_text<S, F, B, A>(
815 text: S,
816 foreground: Option<F>,
817 background: Option<B>,
818 attributes: A,
819 ) -> StyledText
820 where
821 S: Into<String>,
822 F: Into<Color>,
823 B: Into<Color>,
824 A: IntoIterator<Item = Attribute>,
825 {
826 StyledText {
827 text: text.into(),
828 foreground: foreground.map(|c| c.into()),
829 background: background.map(|c| c.into()),
830 attributes: attributes.into_iter().collect(),
831 }
832 }
833
834 pub fn print_styled(styled: StyledText) -> Self {
836 OutputCommand::PrintStyled(styled)
837 }
838}
839
840impl StyledText {
843 pub fn new<S: Into<String>>(text: S) -> Self {
845 StyledText {
846 text: text.into(),
847 foreground: None,
848 background: None,
849 attributes: Vec::new(),
850 }
851 }
852
853 pub fn with_foreground(mut self, color: Color) -> Self {
855 self.foreground = Some(color);
856 self
857 }
858
859 pub fn with_background(mut self, color: Color) -> Self {
861 self.background = Some(color);
862 self
863 }
864
865 pub fn with_attribute(mut self, attribute: Attribute) -> Self {
867 self.attributes.push(attribute);
868 self
869 }
870
871 pub fn with_attributes<I>(mut self, attributes: I) -> Self
873 where
874 I: IntoIterator<Item = Attribute>,
875 {
876 self.attributes.extend(attributes);
877 self
878 }
879}
880
881impl fmt::Display for OutputCommand {
884 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
885 match self {
886 OutputCommand::MoveTo(col, row) => write!(f, "MoveTo({}, {})", col, row),
887 OutputCommand::MoveUp(n) => write!(f, "MoveUp({})", n),
888 OutputCommand::MoveDown(n) => write!(f, "MoveDown({})", n),
889 OutputCommand::MoveLeft(n) => write!(f, "MoveLeft({})", n),
890 OutputCommand::MoveRight(n) => write!(f, "MoveRight({})", n),
891 OutputCommand::MoveToNextLine(n) => write!(f, "MoveToNextLine({})", n),
892 OutputCommand::MoveToPreviousLine(n) => write!(f, "MoveToPreviousLine({})", n),
893 OutputCommand::MoveToColumn(col) => write!(f, "MoveToColumn({})", col),
894 OutputCommand::SavePosition => write!(f, "SavePosition"),
895 OutputCommand::RestorePosition => write!(f, "RestorePosition"),
896 OutputCommand::GetPosition => write!(f, "GetPosition"),
897 OutputCommand::Hide => write!(f, "Hide"),
898 OutputCommand::Show => write!(f, "Show"),
899 OutputCommand::EnableBlinking => write!(f, "EnableBlinking"),
900 OutputCommand::DisableBlinking => write!(f, "DisableBlinking"),
901 OutputCommand::SetCursorStyle(style) => write!(f, "SetCursorStyle({:?})", style),
902
903 OutputCommand::Print(text) => write!(f, "Print({:?})", text),
904 OutputCommand::PrintLine(text) => write!(f, "PrintLine({:?})", text),
905 OutputCommand::PrintStyled(styled) => write!(f, "PrintStyled({:?})", styled.text),
906
907 OutputCommand::SetForegroundColor(color) => {
908 write!(f, "SetForegroundColor({:?})", color)
909 }
910 OutputCommand::SetBackgroundColor(color) => {
911 write!(f, "SetBackgroundColor({:?})", color)
912 }
913 OutputCommand::ResetColor => write!(f, "ResetColor"),
914 OutputCommand::SetColors(fg, bg) => write!(f, "SetColors({:?}, {:?})", fg, bg),
915 OutputCommand::SetAttribute(attr) => write!(f, "SetAttribute({:?})", attr),
916 OutputCommand::ResetAttributes => write!(f, "ResetAttributes"),
917 OutputCommand::SetLineWrap(enable) => write!(f, "SetLineWrap({})", enable),
918
919 OutputCommand::Clear(clear_type) => write!(f, "Clear({:?})", clear_type),
920 OutputCommand::ScrollUp(lines) => write!(f, "ScrollUp({})", lines),
921 OutputCommand::ScrollDown(lines) => write!(f, "ScrollDown({})", lines),
922 OutputCommand::SetSize(cols, rows) => write!(f, "SetSize({}, {})", cols, rows),
923 OutputCommand::GetSize => write!(f, "GetSize"),
924 OutputCommand::EnterAlternateScreen => write!(f, "EnterAlternateScreen"),
925 OutputCommand::LeaveAlternateScreen => write!(f, "LeaveAlternateScreen"),
926 OutputCommand::SetTitle(title) => write!(f, "SetTitle({:?})", title),
927 OutputCommand::EnableMouseCapture => write!(f, "EnableMouseCapture"),
928 OutputCommand::DisableMouseCapture => write!(f, "DisableMouseCapture"),
929 OutputCommand::EnableFocusReporting => write!(f, "EnableFocusReporting"),
930 OutputCommand::DisableFocusReporting => write!(f, "DisableFocusReporting"),
931
932 OutputCommand::PushKeyboardEvent(event) => write!(f, "PushKeyboardEvent({:?})", event),
933 OutputCommand::PushMouseEvent(event) => write!(f, "PushMouseEvent({:?})", event),
934
935 OutputCommand::Batch(commands) => write!(f, "Batch[{} commands]", commands.len()),
936 OutputCommand::If(cond, then_cmd, else_cmd) => {
937 if let Some(else_cmd) = else_cmd {
938 write!(f, "If({}, {:?}, {:?})", cond, then_cmd, else_cmd)
939 } else {
940 write!(f, "If({}, {:?})", cond, then_cmd)
941 }
942 }
943 OutputCommand::Repeat(count, cmd) => write!(f, "Repeat({}, {:?})", count, cmd),
944 }
945 }
946}
947
948impl fmt::Display for Color {
949 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
950 match self {
951 Color::Black => write!(f, "Black"),
952 Color::Red => write!(f, "Red"),
953 Color::Green => write!(f, "Green"),
954 Color::Yellow => write!(f, "Yellow"),
955 Color::Blue => write!(f, "Blue"),
956 Color::Magenta => write!(f, "Magenta"),
957 Color::Cyan => write!(f, "Cyan"),
958 Color::White => write!(f, "White"),
959 Color::BrightBlack => write!(f, "BrightBlack"),
960 Color::BrightRed => write!(f, "BrightRed"),
961 Color::BrightGreen => write!(f, "BrightGreen"),
962 Color::BrightYellow => write!(f, "BrightYellow"),
963 Color::BrightBlue => write!(f, "BrightBlue"),
964 Color::BrightMagenta => write!(f, "BrightMagenta"),
965 Color::BrightCyan => write!(f, "BrightCyan"),
966 Color::BrightWhite => write!(f, "BrightWhite"),
967 Color::Indexed(n) => write!(f, "Indexed({})", n),
968 Color::Rgb(r, g, b) => write!(f, "Rgb({}, {}, {})", r, g, b),
969 Color::Reset => write!(f, "Reset"),
970 }
971 }
972}
973
974impl fmt::Display for Attribute {
975 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
976 match self {
977 Attribute::Bold => write!(f, "Bold"),
978 Attribute::Dim => write!(f, "Dim"),
979 Attribute::Italic => write!(f, "Italic"),
980 Attribute::Underline => write!(f, "Underline"),
981 Attribute::SlowBlink => write!(f, "SlowBlink"),
982 Attribute::RapidBlink => write!(f, "RapidBlink"),
983 Attribute::Reverse => write!(f, "Reverse"),
984 Attribute::Hidden => write!(f, "Hidden"),
985 Attribute::Strikethrough => write!(f, "Strikethrough"),
986 }
987 }
988}
989
990impl fmt::Display for ClearType {
991 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
992 match self {
993 ClearType::All => write!(f, "All"),
994 ClearType::FromCursorDown => write!(f, "FromCursorDown"),
995 ClearType::FromCursorUp => write!(f, "FromCursorUp"),
996 ClearType::CurrentLine => write!(f, "CurrentLine"),
997 ClearType::UntilNewLine => write!(f, "UntilNewLine"),
998 }
999 }
1000}