use super::draw::Cell;
use super::palette::TvColor;
use std::io::{self, Write};
use std::fs::File;
fn color_to_rgb(color: TvColor) -> (u8, u8, u8) {
match color {
TvColor::Black => (0, 0, 0),
TvColor::Blue => (0, 0, 170),
TvColor::Green => (0, 170, 0),
TvColor::Cyan => (0, 170, 170),
TvColor::Red => (170, 0, 0),
TvColor::Magenta => (170, 0, 170),
TvColor::Brown => (170, 85, 0),
TvColor::LightGray => (170, 170, 170),
TvColor::DarkGray => (85, 85, 85),
TvColor::LightBlue => (85, 85, 255),
TvColor::LightGreen => (85, 255, 85),
TvColor::LightCyan => (85, 255, 255),
TvColor::LightRed => (255, 85, 85),
TvColor::LightMagenta => (255, 85, 255),
TvColor::Yellow => (255, 255, 85),
TvColor::White => (255, 255, 255),
}
}
pub fn dump_buffer_to_file(
buffer: &[Vec<Cell>],
width: usize,
height: usize,
path: &str,
) -> io::Result<()> {
let mut file = File::create(path)?;
dump_buffer(&mut file, buffer, width, height)?;
Ok(())
}
pub fn dump_buffer<W: Write>(
writer: &mut W,
buffer: &[Vec<Cell>],
width: usize,
height: usize,
) -> io::Result<()> {
for row in buffer.iter().take(height.min(buffer.len())) {
let mut last_fg = None;
let mut last_bg = None;
for x in 0..width.min(row.len()) {
let cell = row[x];
let need_fg_change = Some(cell.attr.fg) != last_fg;
let need_bg_change = Some(cell.attr.bg) != last_bg;
if need_fg_change || need_bg_change {
if need_fg_change && need_bg_change {
let (fg_r, fg_g, fg_b) = color_to_rgb(cell.attr.fg);
let (bg_r, bg_g, bg_b) = color_to_rgb(cell.attr.bg);
write!(
writer,
"\x1b[38;2;{};{};{};48;2;{};{};{}m",
fg_r, fg_g, fg_b, bg_r, bg_g, bg_b
)?;
} else if need_fg_change {
let (fg_r, fg_g, fg_b) = color_to_rgb(cell.attr.fg);
write!(writer, "\x1b[38;2;{};{};{}m", fg_r, fg_g, fg_b)?;
} else {
let (bg_r, bg_g, bg_b) = color_to_rgb(cell.attr.bg);
write!(writer, "\x1b[48;2;{};{};{}m", bg_r, bg_g, bg_b)?;
}
last_fg = Some(cell.attr.fg);
last_bg = Some(cell.attr.bg);
}
write!(writer, "{}", cell.ch)?;
}
writeln!(writer, "\x1b[0m")?;
}
Ok(())
}
pub fn dump_buffer_region<W: Write>(
writer: &mut W,
buffer: &[Vec<Cell>],
x: usize,
y: usize,
width: usize,
height: usize,
) -> io::Result<()> {
for row in buffer.iter().take((y + height).min(buffer.len())).skip(y) {
let mut last_fg = None;
let mut last_bg = None;
for col in x..(x + width).min(row.len()) {
let cell = row[col];
let need_fg_change = Some(cell.attr.fg) != last_fg;
let need_bg_change = Some(cell.attr.bg) != last_bg;
if need_fg_change || need_bg_change {
if need_fg_change && need_bg_change {
let (fg_r, fg_g, fg_b) = color_to_rgb(cell.attr.fg);
let (bg_r, bg_g, bg_b) = color_to_rgb(cell.attr.bg);
write!(
writer,
"\x1b[38;2;{};{};{};48;2;{};{};{}m",
fg_r, fg_g, fg_b, bg_r, bg_g, bg_b
)?;
} else if need_fg_change {
let (fg_r, fg_g, fg_b) = color_to_rgb(cell.attr.fg);
write!(writer, "\x1b[38;2;{};{};{}m", fg_r, fg_g, fg_b)?;
} else {
let (bg_r, bg_g, bg_b) = color_to_rgb(cell.attr.bg);
write!(writer, "\x1b[48;2;{};{};{}m", bg_r, bg_g, bg_b)?;
}
last_fg = Some(cell.attr.fg);
last_bg = Some(cell.attr.bg);
}
write!(writer, "{}", cell.ch)?;
}
writeln!(writer, "\x1b[0m")?;
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::palette::Attr;
#[test]
fn test_dump_simple_buffer() {
let cells = vec![
Cell::new('H', Attr::new(TvColor::White, TvColor::Blue)),
Cell::new('i', Attr::new(TvColor::White, TvColor::Blue)),
];
let buffer = vec![cells];
let mut output = Vec::new();
dump_buffer(&mut output, &buffer, 2, 1).unwrap();
let result = String::from_utf8(output).unwrap();
assert!(result.contains("Hi"));
assert!(result.contains("\x1b[")); }
}