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
//! 终端格式化模块。
//!
//! 该模块提供了 `Terminal` trait,它抽象了 [ANSI 终端][ansi] 以提供彩色打印等。
//! 有两种实现,一种是 `TerminfoTerminal`,它使用来自 [术语信息][ti] 数据库的控制字符,另一种是 `WinConsole`,它使用 [Win32 控制台 API][win]。
//!
//!
//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
//! [win]: https://docs.microsoft.com/en-us/windows/console/character-mode-applications
//! [ti]: https://en.wikipedia.org/wiki/Terminfo
//!
//!

#![deny(missing_docs)]

use std::io::{self, prelude::*};

pub(crate) use terminfo::TerminfoTerminal;
#[cfg(windows)]
pub(crate) use win::WinConsole;

pub(crate) mod terminfo;

#[cfg(windows)]
mod win;

/// stdout 终端的别名。
pub(crate) type StdoutTerminal = dyn Terminal + Send;

#[cfg(not(windows))]
/// 返回包装 stdout 的终端,如果无法打开终端,则返回 None。
///
pub(crate) fn stdout() -> Option<Box<StdoutTerminal>> {
    TerminfoTerminal::new(io::stdout()).map(|t| Box::new(t) as Box<StdoutTerminal>)
}

#[cfg(windows)]
/// 返回包装 stdout 的终端,如果无法打开终端,则返回 None。
///
pub(crate) fn stdout() -> Option<Box<StdoutTerminal>> {
    TerminfoTerminal::new(io::stdout())
        .map(|t| Box::new(t) as Box<StdoutTerminal>)
        .or_else(|| Some(Box::new(WinConsole::new(io::stdout())) as Box<StdoutTerminal>))
}

/// 终端颜色定义
#[allow(missing_docs)]
#[cfg_attr(not(windows), allow(dead_code))]
pub(crate) mod color {
    /// 终端颜色的编号
    pub(crate) type Color = u32;

    pub(crate) const BLACK: Color = 0;
    pub(crate) const RED: Color = 1;
    pub(crate) const GREEN: Color = 2;
    pub(crate) const YELLOW: Color = 3;
    pub(crate) const BLUE: Color = 4;
    pub(crate) const MAGENTA: Color = 5;
    pub(crate) const CYAN: Color = 6;
    pub(crate) const WHITE: Color = 7;
}

/// 具有与 ANSI 终端 (foreground/background 颜色等) 相似的功能的终端。
///
pub trait Terminal: Write {
    /// 将前景色设置为给定的颜色。
    ///
    /// 如果颜色是亮色,但终端仅支持 8 种颜色,则将使用相应的常规颜色。
    ///
    ///
    /// 如果设置了颜色,则返回 `Ok(true)`,否则返回 `Ok(false)`,如果存在 I/O 错误,则返回 `Err(e)`。
    ///
    fn fg(&mut self, color: color::Color) -> io::Result<bool>;

    /// 将所有终端属性和颜色重置为其默认值。
    ///
    /// 如果重置了终端,则返回 `Ok(true)`; 否则,返回 `Ok(false)`; 如果发生 I/O 错误,则返回 `Err(e)`。
    ///
    /// *Note: 这不会刷新。*
    ///
    /// 这意味着 reset 命令可能会被缓冲,因此,如果您不打算做其他可能会刷新 stdout 缓冲区的事情 (例如,编写一行文本),则应在调用 reset 之后刷新。
    ///
    ///
    ///
    fn reset(&mut self) -> io::Result<bool>;
}