use std::io::{Result, Write};
use termcolor::{ColorSpec, WriteColor};
use crate::{
buffers::Buffers,
table::{Dimension as TableDimension, HorizontalLine, TableFormat, VerticalLine},
};
const ESC: char = '\x1b';
pub(crate) fn display_width(text: &str) -> usize {
let mut width = 0;
let mut chars = text.chars();
#[allow(clippy::while_let_on_iterator)]
while let Some(c) = chars.next() {
if c == ESC {
let Some(c) = chars.next() else {
break;
};
match c {
'\\' => {
}
'[' => while !matches!(chars.next(), Some('\x40'..='\x7C') | None) {},
']' => {
let mut last = c;
while let Some(new) = chars.next() {
if new == '\x07' || (new == '\\' && last == ESC) {
break;
}
last = new;
}
}
_ => {
width += unicode_width::UnicodeWidthChar::width(c).unwrap_or(0);
}
}
} else {
width += unicode_width::UnicodeWidthChar::width(c).unwrap_or(0);
}
}
width
}
pub fn transpose<T>(v: Vec<Vec<T>>) -> Vec<Vec<T>> {
if v.is_empty() || v[0].is_empty() {
return v;
}
let columns = v.len();
let height = v[0].len();
let mut optional_v: Vec<Vec<Option<T>>> = v
.into_iter()
.map(|cell_v| cell_v.into_iter().map(Some).collect())
.collect();
let mut transpose = Vec::with_capacity(height);
for i in 0..height {
let mut row_buffer = Vec::with_capacity(columns);
for inner_v in optional_v.iter_mut().take(columns) {
row_buffer.push(std::mem::take(&mut inner_v[i]).unwrap());
}
transpose.push(row_buffer);
}
transpose
}
pub(crate) fn print_horizontal_line(
buffers: &mut Buffers<'_>,
line: Option<&HorizontalLine>,
table_dimension: &TableDimension,
table_format: &TableFormat,
color_spec: &ColorSpec,
) -> Result<()> {
if let Some(line) = line {
if table_format.border.left.is_some() {
print_char(buffers, line.left_end, color_spec)?;
}
let mut widths = table_dimension.widths.iter().peekable();
while let Some(width) = widths.next() {
let s = std::iter::repeat(line.filler)
.take(width + 2)
.collect::<String>();
print_str(buffers, &s, color_spec)?;
match widths.peek() {
Some(_) => {
if table_format.separator.column.is_some() {
print_char(buffers, line.junction, color_spec)?
}
}
None => {
if table_format.border.right.is_some() {
print_char(buffers, line.right_end, color_spec)?;
} else {
print_str(buffers, "", color_spec)?;
}
}
}
}
println(buffers)?;
}
Ok(())
}
pub(crate) fn print_vertical_line(
buffers: &mut Buffers<'_>,
line: Option<&VerticalLine>,
color_spec: &ColorSpec,
) -> Result<()> {
if let Some(line) = line {
print_char(buffers, line.filler, color_spec)?;
}
Ok(())
}
pub(crate) fn print_str(buffers: &mut Buffers<'_>, s: &str, color_spec: &ColorSpec) -> Result<()> {
buffers.set_color(color_spec)?;
write!(buffers, "{}", s)?;
buffers.reset()
}
pub(crate) fn print_char(buffers: &mut Buffers<'_>, c: char, color_spec: &ColorSpec) -> Result<()> {
buffers.set_color(color_spec)?;
write!(buffers, "{}", c)?;
buffers.reset()
}
pub(crate) fn println(buffers: &mut Buffers<'_>) -> Result<()> {
writeln!(buffers)
}