xacli_core/io/output/
command.rs

1use std::{
2    fmt,
3    io::{self, Write},
4};
5
6// ========== 基础类型定义 ==========
7
8/// ANSI 颜色类型
9#[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    /// 8位颜色 (0-255)
28    Indexed(u8),
29    /// RGB 颜色 (r, g, b)
30    Rgb(u8, u8, u8),
31    /// 重置颜色
32    Reset,
33}
34
35/// 文本属性
36#[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/// 清除类型
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51pub enum ClearType {
52    All,
53    FromCursorDown,
54    FromCursorUp,
55    CurrentLine,
56    UntilNewLine,
57}
58
59/// 鼠标按钮
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub enum MouseButton {
62    Left,
63    Right,
64    Middle,
65}
66
67/// 鼠标事件类型
68#[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/// 鼠标事件
79#[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/// 修饰键
88#[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/// 键盘按键
97#[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/// 键盘事件
127#[derive(Debug, Clone, Copy, PartialEq, Eq)]
128pub struct KeyEvent {
129    pub code: KeyCode,
130    pub modifiers: Modifiers,
131}
132
133// ========== OutputCommand 枚举 ==========
134
135/// 完整的终端控制命令枚举
136#[derive(Debug, Clone)]
137pub enum OutputCommand {
138    // ========== 光标控制 ==========
139    /// 移动光标到指定位置 (列, 行),从 (1,1) 开始
140    MoveTo(u16, u16),
141    /// 光标上移 n 行
142    MoveUp(u16),
143    /// 光标下移 n 行
144    MoveDown(u16),
145    /// 光标左移 n 列
146    MoveLeft(u16),
147    /// 光标右移 n 列
148    MoveRight(u16),
149    /// 光标移动到下一行,列位置不变
150    MoveToNextLine(u16),
151    /// 光标移动到上一行,列位置不变
152    MoveToPreviousLine(u16),
153    /// 光标移动到指定列
154    MoveToColumn(u16),
155    /// 保存光标位置
156    SavePosition,
157    /// 恢复光标位置
158    RestorePosition,
159    /// 获取光标位置(返回 (列, 行))
160    GetPosition,
161    /// 隐藏光标
162    Hide,
163    /// 显示光标
164    Show,
165    /// 启用光标闪烁
166    EnableBlinking,
167    /// 禁用光标闪烁
168    DisableBlinking,
169    /// 设置光标形状
170    SetCursorStyle(CursorStyle),
171
172    // ========== 文本输出 ==========
173    /// 打印文本
174    Print(String),
175    /// 打印一行文本(自动换行)
176    PrintLine(String),
177    /// 打印带样式的文本
178    PrintStyled(StyledText),
179
180    // ========== 颜色和样式 ==========
181    /// 设置前景色
182    SetForegroundColor(Color),
183    /// 设置背景色
184    SetBackgroundColor(Color),
185    /// 重置颜色(前景和背景)
186    ResetColor,
187    /// 同时设置前景和背景色
188    SetColors(Color, Color),
189    /// 设置文本属性
190    SetAttribute(Attribute),
191    /// 重置所有样式
192    ResetAttributes,
193    /// 启用/禁用自动换行
194    SetLineWrap(bool),
195
196    // ========== 终端控制 ==========
197    /// 清除屏幕
198    Clear(ClearType),
199    /// 滚动屏幕
200    ScrollUp(u16),
201    ScrollDown(u16),
202    /// 设置终端大小
203    SetSize(u16, u16),
204    /// 获取终端大小
205    GetSize,
206    /// 进入备用屏幕缓冲区
207    EnterAlternateScreen,
208    /// 退出备用屏幕缓冲区
209    LeaveAlternateScreen,
210    /// 设置终端标题
211    SetTitle(String),
212    /// 启用鼠标捕获
213    EnableMouseCapture,
214    /// 禁用鼠标捕获
215    DisableMouseCapture,
216    /// 启用焦点事件报告
217    EnableFocusReporting,
218    /// 禁用焦点事件报告
219    DisableFocusReporting,
220
221    // ========== 事件相关 ==========
222    /// 推送键盘事件(用于模拟输入)
223    PushKeyboardEvent(KeyEvent),
224    /// 推送鼠标事件(用于模拟输入)
225    PushMouseEvent(MouseEvent),
226
227    // ========== 高级/组合命令 ==========
228    /// 执行多个命令
229    Batch(Vec<OutputCommand>),
230    /// 条件执行
231    If(bool, Box<OutputCommand>, Option<Box<OutputCommand>>),
232    /// 循环执行
233    Repeat(u32, Box<OutputCommand>),
234}
235
236/// 光标样式
237#[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/// 带样式的文本
249#[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
257// ========== ANSI 转义序列实现 ==========
258
259impl OutputCommand {
260    /// 执行命令
261    pub fn execute(&self, writer: &mut dyn Write) -> io::Result<()> {
262        self.write_ansi(writer, true)
263    }
264
265    /// 排队命令(不立即刷新)
266    pub fn queue(&self, writer: &mut dyn Write) -> io::Result<()> {
267        self.write_ansi(writer, false)
268    }
269
270    /// 将命令写入 ANSI 序列
271    fn write_ansi(&self, writer: &mut dyn Write, flush: bool) -> io::Result<()> {
272        match self {
273            // ========== 光标控制 ==========
274            OutputCommand::MoveTo(col, row) => {
275                // CSI n ; m H - 光标定位
276                write!(writer, "\x1b[{};{}H", row, col)?;
277            }
278            OutputCommand::MoveUp(n) => {
279                // CSI n A - 光标上移
280                if *n > 0 {
281                    write!(writer, "\x1b[{}A", n)?;
282                }
283            }
284            OutputCommand::MoveDown(n) => {
285                // CSI n B - 光标下移
286                if *n > 0 {
287                    write!(writer, "\x1b[{}B", n)?;
288                }
289            }
290            OutputCommand::MoveLeft(n) => {
291                // CSI n D - 光标左移
292                if *n > 0 {
293                    write!(writer, "\x1b[{}D", n)?;
294                }
295            }
296            OutputCommand::MoveRight(n) => {
297                // CSI n C - 光标右移
298                if *n > 0 {
299                    write!(writer, "\x1b[{}C", n)?;
300                }
301            }
302            OutputCommand::MoveToNextLine(n) => {
303                // CSI n E - 光标移动到下几行的开头
304                if *n > 0 {
305                    write!(writer, "\x1b[{}E", n)?;
306                }
307            }
308            OutputCommand::MoveToPreviousLine(n) => {
309                // CSI n F - 光标移动到上几行的开头
310                if *n > 0 {
311                    write!(writer, "\x1b[{}F", n)?;
312                }
313            }
314            OutputCommand::MoveToColumn(col) => {
315                // CSI n G - 光标移动到指定列
316                write!(writer, "\x1b[{}G", col)?;
317            }
318            OutputCommand::SavePosition => {
319                // ESC 7 - 保存光标位置
320                write!(writer, "\x1b7")?;
321            }
322            OutputCommand::RestorePosition => {
323                // ESC 8 - 恢复光标位置
324                write!(writer, "\x1b8")?;
325            }
326            OutputCommand::GetPosition => {
327                // CSI 6 n - 请求光标位置(终端会响应)
328                write!(writer, "\x1b[6n")?;
329            }
330            OutputCommand::Hide => {
331                // CSI ? 25 l - 隐藏光标
332                write!(writer, "\x1b[?25l")?;
333            }
334            OutputCommand::Show => {
335                // CSI ? 25 h - 显示光标
336                write!(writer, "\x1b[?25h")?;
337            }
338            OutputCommand::EnableBlinking => {
339                // CSI ? 12 h - 启用光标闪烁
340                write!(writer, "\x1b[?12h")?;
341            }
342            OutputCommand::DisableBlinking => {
343                // CSI ? 12 l - 禁用光标闪烁
344                write!(writer, "\x1b[?12l")?;
345            }
346            OutputCommand::SetCursorStyle(style) => {
347                // CSI Ps SP q - 设置光标样式
348                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            // ========== 文本输出 ==========
361            OutputCommand::Print(text) => {
362                write!(writer, "{}", text)?;
363            }
364            OutputCommand::PrintLine(text) => {
365                write!(writer, "{}\r\n", text)?;
366            }
367            OutputCommand::PrintStyled(styled) => {
368                // 应用样式
369                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                // 写入文本
380                write!(writer, "{}", styled.text)?;
381
382                // 重置样式
383                if !styled.attributes.is_empty() {
384                    write!(writer, "\x1b[0m")?;
385                }
386            }
387
388            // ========== 颜色和样式 ==========
389            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                // 重置颜色(前景色和背景色)
397                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                // 重置所有属性
408                write!(writer, "\x1b[0m")?;
409            }
410            OutputCommand::SetLineWrap(enable) => {
411                if *enable {
412                    // CSI ? 7 h - 启用自动换行
413                    write!(writer, "\x1b[?7h")?;
414                } else {
415                    // CSI ? 7 l - 禁用自动换行
416                    write!(writer, "\x1b[?7l")?;
417                }
418            }
419
420            // ========== 终端控制 ==========
421            OutputCommand::Clear(clear_type) => {
422                match clear_type {
423                    ClearType::All => {
424                        // CSI 2 J - 清除整个屏幕
425                        write!(writer, "\x1b[2J")?;
426                    }
427                    ClearType::FromCursorDown => {
428                        // CSI 0 J - 清除从光标到屏幕末尾
429                        write!(writer, "\x1b[0J")?;
430                    }
431                    ClearType::FromCursorUp => {
432                        // CSI 1 J - 清除从光标到屏幕开头
433                        write!(writer, "\x1b[1J")?;
434                    }
435                    ClearType::CurrentLine => {
436                        // CSI 2 K - 清除整行
437                        write!(writer, "\x1b[2K")?;
438                    }
439                    ClearType::UntilNewLine => {
440                        // CSI 0 K - 清除从光标到行尾
441                        write!(writer, "\x1b[0K")?;
442                    }
443                }
444            }
445            OutputCommand::ScrollUp(lines) => {
446                // CSI n S - 向上滚动 n 行
447                if *lines > 0 {
448                    write!(writer, "\x1b[{}S", lines)?;
449                }
450            }
451            OutputCommand::ScrollDown(lines) => {
452                // CSI n T - 向下滚动 n 行
453                if *lines > 0 {
454                    write!(writer, "\x1b[{}T", lines)?;
455                }
456            }
457            OutputCommand::SetSize(cols, rows) => {
458                // 大多数终端不支持动态调整大小
459                // 但我们可以输出一个请求(不是所有终端都支持)
460                write!(writer, "\x1b[8;{};{}t", rows, cols)?;
461            }
462            OutputCommand::GetSize => {
463                // CSI 18 t - 获取终端大小
464                write!(writer, "\x1b[18t")?;
465            }
466            OutputCommand::EnterAlternateScreen => {
467                // CSI ? 1049 h - 进入备用屏幕缓冲区
468                write!(writer, "\x1b[?1049h")?;
469            }
470            OutputCommand::LeaveAlternateScreen => {
471                // CSI ? 1049 l - 退出备用屏幕缓冲区
472                write!(writer, "\x1b[?1049l")?;
473            }
474            OutputCommand::SetTitle(title) => {
475                // OSC 0 ; title BEL - 设置窗口标题
476                write!(writer, "\x1b]0;{}\x07", title)?;
477            }
478            OutputCommand::EnableMouseCapture => {
479                // CSI ? 1000 h - 启用鼠标报告
480                write!(writer, "\x1b[?1000h")?;
481                // CSI ? 1002 h - 启用鼠标拖动报告
482                write!(writer, "\x1b[?1002h")?;
483                // CSI ? 1006 h - 启用 SGR 扩展鼠标模式
484                write!(writer, "\x1b[?1006h")?;
485            }
486            OutputCommand::DisableMouseCapture => {
487                // CSI ? 1006 l - 禁用 SGR 扩展鼠标模式
488                write!(writer, "\x1b[?1006l")?;
489                // CSI ? 1002 l - 禁用鼠标拖动报告
490                write!(writer, "\x1b[?1002l")?;
491                // CSI ? 1000 l - 禁用鼠标报告
492                write!(writer, "\x1b[?1000l")?;
493            }
494            OutputCommand::EnableFocusReporting => {
495                // CSI ? 1004 h - 启用焦点事件报告
496                write!(writer, "\x1b[?1004h")?;
497            }
498            OutputCommand::DisableFocusReporting => {
499                // CSI ? 1004 l - 禁用焦点事件报告
500                write!(writer, "\x1b[?1004l")?;
501            }
502
503            // ========== 事件相关 ==========
504            OutputCommand::PushKeyboardEvent(event) => {
505                // 键盘事件通常不能直接输出到终端
506                // 这通常用于模拟或测试
507                // 我们只是记录,不实际输出
508                let _ = event;
509            }
510            OutputCommand::PushMouseEvent(event) => {
511                // 同上,只是记录
512                let _ = event;
513            }
514
515            // ========== 高级/组合命令 ==========
516            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    /// 写入颜色 ANSI 序列
543    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    /// 写入属性 ANSI 序列
689    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    // ========== 便利构造函数 ==========
760
761    /// 创建打印命令
762    pub fn print<S: Into<String>>(text: S) -> Self {
763        OutputCommand::Print(text.into())
764    }
765
766    /// 创建打印行命令
767    pub fn print_line<S: Into<String>>(text: S) -> Self {
768        OutputCommand::PrintLine(text.into())
769    }
770
771    /// 创建移动光标命令
772    pub fn move_to(col: u16, row: u16) -> Self {
773        OutputCommand::MoveTo(col, row)
774    }
775
776    /// 创建清屏命令
777    pub fn clear(clear_type: ClearType) -> Self {
778        OutputCommand::Clear(clear_type)
779    }
780
781    /// 创建设置颜色命令
782    pub fn set_colors(foreground: Color, background: Color) -> Self {
783        OutputCommand::SetColors(foreground, background)
784    }
785
786    /// 创建批处理命令
787    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    /// 创建条件命令
795    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    /// 创建重复命令
806    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    /// 创建带样式的文本
814    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    /// 从带样式的文本创建命令
835    pub fn print_styled(styled: StyledText) -> Self {
836        OutputCommand::PrintStyled(styled)
837    }
838}
839
840// ========== 为 StyledText 实现方法 ==========
841
842impl StyledText {
843    /// 创建新的带样式文本
844    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    /// 设置前景色
854    pub fn with_foreground(mut self, color: Color) -> Self {
855        self.foreground = Some(color);
856        self
857    }
858
859    /// 设置背景色
860    pub fn with_background(mut self, color: Color) -> Self {
861        self.background = Some(color);
862        self
863    }
864
865    /// 添加属性
866    pub fn with_attribute(mut self, attribute: Attribute) -> Self {
867        self.attributes.push(attribute);
868        self
869    }
870
871    /// 添加多个属性
872    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
881// ========== 实现 Display trait ==========
882
883impl 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}