///|
/// 终端颜色:默认色、256 索引色、真彩色 RGB。
pub(all) enum TermColor {
Default
Indexed(Int)
Rgb(Int, Int, Int)
} derive(Eq, Debug)
///|
pub extend TermColor with Debug::{to_repr}
///|
pub extend TermColor with Eq::{not_equal, equal}
///|
/// 单元格属性(SGR 状态)。
pub(all) struct CellAttrs {
fg : TermColor
bg : TermColor
bold : Bool
dim : Bool
italic : Bool
underline : Bool
reverse : Bool
} derive(Eq, Debug)
///|
pub extend CellAttrs with Debug::{to_repr}
///|
pub extend CellAttrs with Eq::{not_equal, equal}
///|
pub fn CellAttrs::default() -> CellAttrs {
{
fg: Default,
bg: Default,
bold: false,
dim: false,
italic: false,
underline: false,
reverse: false,
}
}
///|
/// 复制属性并替换部分字段(SGR 序列用)。
pub fn attrs_with(
attrs : CellAttrs,
fg? : TermColor? = None,
bg? : TermColor? = None,
bold? : Bool? = None,
dim? : Bool? = None,
italic? : Bool? = None,
underline? : Bool? = None,
reverse? : Bool? = None,
) -> CellAttrs {
{
fg: match fg {
Some(v) => v
None => attrs.fg
},
bg: match bg {
Some(v) => v
None => attrs.bg
},
bold: match bold {
Some(v) => v
None => attrs.bold
},
dim: match dim {
Some(v) => v
None => attrs.dim
},
italic: match italic {
Some(v) => v
None => attrs.italic
},
underline: match underline {
Some(v) => v
None => attrs.underline
},
reverse: match reverse {
Some(v) => v
None => attrs.reverse
},
}
}
///|
/// 复制属性并替换前景色。
pub fn attrs_with_fg(attrs : CellAttrs, fg : TermColor) -> CellAttrs {
attrs_with(attrs, fg=Some(fg))
}
///|
/// 单元格:一个字符(宽字符占两格,第二格为 continuation,ch 为空)。
pub(all) struct Cell {
ch : String
width : Int
attrs : CellAttrs
} derive(Eq, Debug)
///|
pub extend Cell with Debug::{to_repr}
///|
pub extend Cell with Eq::{not_equal, equal}
///|
pub fn blank_cell(attrs : CellAttrs) -> Cell {
{ ch: " ", width: 1, attrs, }
}
///|
/// 宽字符右半格:`width == 0` 让它不产生文本,只继承底色。
pub fn continuation_cell(attrs : CellAttrs) -> Cell {
{ ch: "", width: 0, attrs, }
}
///|
/// 提取字符串首字符的 Unicode 码点(String::at 返回 UTF-16 code unit)。
fn utf8_codepoint(s : String) -> Int {
let u = s[0].to_int()
if u >= 0xD800 && u <= 0xDBFF && s.length() >= 2 {
let lo = s[1].to_int()
0x10000 + ((u - 0xD800) << 10) + (lo - 0xDC00)
} else {
u
}
}
///|
/// 简化 wcwidth:ASCII 1,常见宽字符区间 2,其余 1。
/// 组合符未合并进基字符格,按 1 计(投影器不区分带符与基符)。
pub fn unicode_width(ch : String) -> Int {
let cp = utf8_codepoint(ch)
if cp >= 0x20 && cp <= 0x7E {
return 1
}
if (cp >= 0x1100 && cp <= 0x115F) ||
(cp >= 0x2E80 && cp <= 0xA4CF) ||
(cp >= 0xAC00 && cp <= 0xD7A3) ||
(cp >= 0xF900 && cp <= 0xFAFF) ||
(cp >= 0xFE30 && cp <= 0xFE4F) ||
(cp >= 0xFF00 && cp <= 0xFF60) ||
(cp >= 0xFFE0 && cp <= 0xFFE6) ||
(cp >= 0x1F300 && cp <= 0x1FAFF) ||
(cp >= 0x20000 && cp <= 0x3FFFD) {
return 2
}
1
}