///|
/// 屏幕上的一个单元格
pub struct Cell {
char : Char
format : ConsoleFormat
} derive(Eq)
///|
pub fn Cell::new(char : Char, format : ConsoleFormat) -> Cell {
{ char, format }
}
///|
pub impl Default for Cell with default() -> Cell {
{ char: ' ', format: ConsoleFormat::default() }
}
///|
/// 判断两个单元格是否完全一致(内容和样式)
pub fn Cell::op_equal(self : Cell, other : Cell) -> Bool {
self.char == other.char &&
self.format.foreground == other.format.foreground &&
self.format.background == other.format.background &&
self.format.bold == other.format.bold &&
self.format.italic == other.format.italic &&
self.format.underline == other.format.underline
}
///|
/// 虚拟屏幕缓冲区
pub struct Screen {
rows : Array[Array[Cell]]
width : Int
height : Int
mut cursor_row : Int
mut cursor_col : Int
}
///|
pub fn Screen::set_cursor(self : Screen, row : Int, col : Int) -> Unit {
self.cursor_row = row
self.cursor_col = col
}
///|
/// 创建指定大小的空屏幕
pub fn Screen::new(height : Int, width : Int) -> Screen {
let rows = Array::new(capacity=height)
for _ in 0.. Unit {
if row < 0 || row >= self.height {
return
}
let mut current_col = col
for ch in text {
let w = get_char_width(ch)
if current_col + w > self.width {
break
}
if current_col >= 0 {
self.rows[row][current_col] = Cell::new(ch, format)
// 如果是宽字符,后续格子标记为空白以防重叠渲染逻辑出错
if w == 2 && current_col + 1 < self.width {
self.rows[row][current_col + 1] = Cell::new('\u{0000}', format)
}
}
current_col = current_col + w
}
}
///|
fn append_relative_cursor_move(
output : Array[String],
from_row : Int,
from_col : Int,
to_row : Int,
to_col : Int,
) -> Unit {
let row_delta = to_row - from_row
if row_delta < 0 {
output.push("\u{1b}[\{-row_delta}A")
} else if row_delta > 0 {
output.push("\u{1b}[\{row_delta}B")
}
let col_delta = to_col - from_col
if col_delta < 0 {
output.push("\u{1b}[\{-col_delta}D")
} else if col_delta > 0 {
output.push("\u{1b}[\{col_delta}C")
}
}
///|
/// 将新旧屏幕差异输出到控制台
pub fn render_diff(
console : &@ports.ConsolePort,
new_screen : Screen,
old_screen : Screen,
base_row : Int,
base_col : Int,
) -> Unit {
let output = Array::new()
let mut current_format = ConsoleFormat::default()
output.push("\u{1b}[0m") // 重置初始样式
// 首帧仍用绝对定位建立锚点;后续刷新使用相对移动。
let mut cursor_row = old_screen.cursor_row
let mut cursor_col = old_screen.cursor_col
if old_screen.height == 0 {
output.push("\u{1b}[\{base_row};\{base_col}H")
cursor_row = 0
cursor_col = 0
}
let max_height = if new_screen.height > old_screen.height {
new_screen.height
} else {
old_screen.height
}
let max_width = if new_screen.width > old_screen.width {
new_screen.width
} else {
old_screen.width
}
for r in 0..