use crate::{
asset::{Asset, AssetBase},
render::image::find_vaild_area,
render::buffer::Buffer,
render::style::{Color, Style},
util::Rect,
};
use log::info;
use regex::Regex;
use std::io::{BufRead, BufReader, Write};
use unicode_width::UnicodeWidthStr;
pub struct EscAsset {
base: AssetBase,
}
impl Asset for EscAsset {
fn new(ab: AssetBase) -> Self {
Self { base: ab }
}
fn get_base(&mut self) -> &mut AssetBase {
&mut self.base
}
fn parse(&mut self) {
self.base.parsed_buffers.clear();
let size = Rect::new(0, 0, 500, 300);
let mut sp = Buffer::empty(size);
let reader = BufReader::new(&self.base.raw_data[..]);
let mut row = 0;
let mut max_width: u16 = 0;
for line in reader.lines() {
let l = line.unwrap();
let lw = escstr_to_buffer(&l, &mut sp, row, 0, 0);
if lw > max_width {
max_width = lw;
}
row += 1;
}
let nsize = Rect::new(0, 0, max_width, row);
let mut nsp = Buffer::empty(nsize);
let _ = nsp.blit(0, 0, &sp, nsize, 255);
self.base.parsed_buffers.push(nsp);
}
fn save(&mut self, content: &Buffer) {
self.base.raw_data.clear();
let mut ptr = std::io::Cursor::new(&mut self.base.raw_data);
let width = content.area.width;
let (x1, x2, y1, y2) = find_vaild_area(content);
for row in y1..y2 + 1 {
let line =
&content.content[(row * width + x1) as usize..(row * width + x2 + 1) as usize];
let mut fg = Color::Reset;
let mut bg = Color::Reset;
let mut span = String::new();
let mut skip = 0i8;
for cell in line.iter() {
info!(
"save_esc symbol={} symwidth={}",
cell.symbol,
cell.symbol.width()
);
if skip > 0 {
info!("skip, skip={}", skip);
skip -= 1;
continue;
}
let sw = cell.symbol.width();
if sw > 1 {
skip = sw as i8;
skip -= 1;
info!("set skip, skip={}", skip);
}
if cell.fg != fg || cell.bg != bg {
if !span.is_empty() {
if fg == Color::Reset && bg == Color::Reset {
let _ = ptr.write_all(span.as_bytes());
} else {
let ss = format!(
"\x1b[38;5;{}m\x1b[48;5;{}m{}\x1b[0m",
u8::from(fg),
u8::from(bg),
span
);
let _ = ptr.write_all(ss.as_bytes());
}
span.clear();
}
fg = cell.fg;
bg = cell.bg;
span.push_str(&cell.symbol);
} else {
span.push_str(&cell.symbol);
}
}
if !span.is_empty() {
if fg == Color::Reset && bg == Color::Reset {
let _ = ptr.write_all(span.as_bytes());
} else {
let ss = format!(
"\x1b[38;5;{}m\x1b[48;5;{}m{}\x1b[0m",
u8::from(fg),
u8::from(bg),
span
);
let _ = ptr.write_all(ss.as_bytes());
}
span.clear();
}
let _ = ptr.write_all("\n".as_bytes());
}
}
}
pub fn escstr_to_buffer(l: &str, content: &mut Buffer, row: u16, off_x: u16, off_y: u16) -> u16 {
let mut pos = 0;
let mut cell_pos = 0;
let mut lpos = 0;
let mut lcell_pos = 0;
let re = Regex::new(r"\x1b\[38;5;(\d+)m\x1b\[48;5;(\d+)m(.*?)\x1b\[0m").unwrap();
for cap in re.captures_iter(l) {
let cr = cap.get(0).unwrap();
content.set_str(
cell_pos + off_x,
row + off_y,
&l[pos..cr.start()],
Style::default(),
);
cell_pos += l[pos..cr.start()].width() as u16;
content.set_str(
cell_pos + off_x,
row + off_y,
&cap[3],
Style::default()
.fg(Color::Indexed(cap[1].parse::<u8>().unwrap()))
.bg(Color::Indexed(cap[2].parse::<u8>().unwrap())),
);
cell_pos += cap[3].width() as u16;
pos = cr.end();
lpos = pos;
lcell_pos = cell_pos;
}
content.set_str(
lcell_pos + off_x,
row + off_y,
&l[lpos..l.len()],
Style::default(),
);
lcell_pos + l[lpos..l.len()].width() as u16
}