use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::style::{Color, Modifier, Style};
use ratatui::widgets::Widget;
pub struct VtTerminal {
parser: vt100::Parser,
}
impl VtTerminal {
pub fn new(cols: u16, rows: u16) -> Self {
Self {
parser: vt100::Parser::new(rows, cols, 0),
}
}
pub fn process(&mut self, data: &[u8]) {
self.parser.process(data);
}
pub fn resize(&mut self, rows: u16, cols: u16) {
self.parser.set_size(rows, cols);
}
pub fn widget(&self) -> VtWidget<'_> {
VtWidget {
screen: self.parser.screen(),
}
}
}
pub struct VtWidget<'a> {
screen: &'a vt100::Screen,
}
impl Widget for VtWidget<'_> {
fn render(self, area: Rect, buf: &mut Buffer) {
let rows = area.height.min(self.screen.size().0);
let cols = area.width.min(self.screen.size().1);
for row in 0..rows {
for col in 0..cols {
let cell = self.screen.cell(row, col);
if let Some(cell) = cell {
let x = area.x + col;
let y = area.y + row;
if x < area.right() && y < area.bottom() {
let ch = cell.contents();
let fg = vt100_color_to_ratatui(cell.fgcolor());
let bg = vt100_color_to_ratatui(cell.bgcolor());
let mut style = Style::default().fg(fg).bg(bg);
if cell.bold() {
style = style.add_modifier(Modifier::BOLD);
}
if cell.underline() {
style = style.add_modifier(Modifier::UNDERLINED);
}
if cell.inverse() {
style = style.add_modifier(Modifier::REVERSED);
}
let buf_cell = buf.cell_mut((x, y));
if let Some(buf_cell) = buf_cell {
buf_cell.set_symbol(if ch.is_empty() { " " } else { &ch });
buf_cell.set_style(style);
}
}
}
}
}
}
}
fn vt100_color_to_ratatui(color: vt100::Color) -> Color {
match color {
vt100::Color::Default => Color::Reset,
vt100::Color::Idx(i) => Color::Indexed(i),
vt100::Color::Rgb(r, g, b) => Color::Rgb(r, g, b),
}
}