extern crate enable_ansi_support;
use enable_ansi_support::enable_ansi_support;
use terminal_size::{terminal_size, Width};
use crate::chars::{
add_letter, add_line, add_line_height, align_last_line, get_letter_length, get_letter_space, paint_letter,
};
use crate::color::{bgcolor2hex, get_background_color};
use crate::config::{Align, BgColors, Env, Options};
use crate::debug::{d, Dt};
use crate::font;
use crate::gradient::add_gradient_colors;
pub struct RenderedString {
pub text: String,
pub vec: Vec<String>,
pub lines: usize,
pub options: Options,
}
pub fn render(options: Options) -> RenderedString {
d("render()", 1, Dt::Head, &options, &mut std::io::stdout());
d(&format!("render() Options\n{:#?}", options), 1, Dt::Log, &options, &mut std::io::stdout());
if let Ok(()) = enable_ansi_support() {
d("render() enabled ansi support in windows", 2, Dt::Log, &options, &mut std::io::stdout());
}
let size = terminal_size();
let terminal_width = match options.env {
Env::Cli => {
if let Some((Width(w), _)) = size {
w
} else {
80
}
}
Env::Browser => 0xFFFF,
};
d(&format!("render()\nterminal_width:{:?}", terminal_width), 1, Dt::Log, &options, &mut std::io::stdout());
let fonts = font::load_all_fonts();
let mut font = font::get(&fonts, &options);
let mut line_length = 0;
let mut letter_count = 0;
let mut lines = 0;
let mut output: Vec<String> = Vec::new();
let letter_spacing = if font.letterspace_size == 0 && options.letter_spacing > 0 {
options.letter_spacing - 1
} else {
options.letter_spacing
};
d(&format!("render()\nletter_spacing:{:?}", letter_spacing), 1, Dt::Log, &options, &mut std::io::stdout());
let letter_space = get_letter_space(&font.letterspace, letter_spacing, &options);
let letter_space_len = get_letter_length(&letter_space, font.colors, &options);
let painted_letter_space = paint_letter(&letter_space, font.colors, &options);
d(
&format!(
"render()\nletter_space:{:?}\nletter_space_len:{:?}\npainted_letter_space:{:?}",
letter_space, letter_space_len, painted_letter_space
),
2,
Dt::Log,
&options,
&mut std::io::stdout(),
);
let line_break = if options.env == Env::Cli && options.raw_mode {
"\r\n"
} else {
"\n"
};
add_line(&mut output, font.lines, &options);
lines += 1;
add_letter(&mut output, &font.buffer, &options);
let buffer_len = get_letter_length(&font.buffer, font.lines, &options);
line_length += buffer_len;
d("render() added buffer", 1, Dt::Log, &options, &mut std::io::stdout());
options.text.chars().for_each(|og_letter| {
d(&format!("render() \u{2022} loop og_letter:{:?}", og_letter), 1, Dt::Log, &options, &mut std::io::stdout());
font.chars.insert(String::from("|"), vec![String::from("|")]);
match font.chars.get(&og_letter.to_string().to_uppercase()) {
None => {
d(&format!("render() ignoring unknown letter:{:?}", og_letter), 1, Dt::Log, &options, &mut std::io::stdout());
}
Some(font_letter) => {
d(&format!("render()\nfont_letter:{:?}", font_letter), 2, Dt::Log, &options, &mut std::io::stdout());
let this_letter_len = get_letter_length(font_letter, font.colors, &options);
if font_letter[0] == "|"
|| this_letter_len + letter_space_len + line_length > terminal_width.into()
|| letter_count + 1 > options.max_length && options.max_length > 0
{
d(
&format!("render() added new line because\nletter == |:{:?}\nnew_length({:?}) > terminal_width({:?})\nnew_letter_count({:?}) > max_length({:?})",
font_letter[0] == "|",
this_letter_len + letter_space_len + line_length,
terminal_width,
letter_count + 1,
options.max_length
),
1,
Dt::Log,
&options,
&mut std::io::stdout()
);
align_last_line(&mut output, font.lines, line_length, terminal_width.into(), &options);
d("render() aligned last line", 1, Dt::Log, &options, &mut std::io::stdout());
add_line(&mut output, font.lines, &options);
d("render() added new line", 1, Dt::Log, &options, &mut std::io::stdout());
add_line_height(&mut output, options.line_height, &options);
d("render() added line_height", 1, Dt::Log, &options, &mut std::io::stdout());
add_letter(&mut output, &font.buffer, &options);
d("render() added buffer", 1, Dt::Log, &options, &mut std::io::stdout());
line_length = buffer_len;
lines += 1;
letter_count = 0;
}
if font_letter[0] != "|" {
let painted_letter = paint_letter(font_letter, font.colors, &options);
d("render() added color to letter", 1, Dt::Log, &options, &mut std::io::stdout());
d(&format!("render()\npainted_letter:{:?}", painted_letter), 2, Dt::Log, &options, &mut std::io::stdout());
add_letter(&mut output, &painted_letter_space, &options);
d("render() added letter_space", 1, Dt::Log, &options, &mut std::io::stdout());
add_letter(&mut output, &painted_letter, &options);
d("render() added letter", 1, Dt::Log, &options, &mut std::io::stdout());
letter_count += 1;
line_length += letter_space_len + this_letter_len;
}
}
}
});
align_last_line(&mut output, font.lines, line_length, terminal_width.into(), &options);
d("render() aligned last line", 1, Dt::Log, &options, &mut std::io::stdout());
if !options.gradient.is_empty() {
output = add_gradient_colors(&output, lines, font.lines, &options);
d("render() added gradient colors", 1, Dt::Log, &options, &mut std::io::stdout());
}
if !options.spaceless {
match options.align {
Align::Top => output.push(format!("{line_break}{line_break}{line_break}")),
Align::Bottom => output[0] = format!("{line_break}{line_break}{line_break}{line_break}") + &output[0],
Align::Left | Align::Center | Align::Right => {
output[0] = format!("{line_break}{line_break}") + &output[0];
let last_index = output.len() - 1;
output[last_index] = format!("{}{line_break}{line_break}", output[last_index]);
}
}
d("render() added space", 1, Dt::Log, &options, &mut std::io::stdout());
}
if options.background != BgColors::Transparent && options.env == Env::Cli {
let (open, close) = get_background_color(&options.background);
output[0] = format!("{}{line_break}", open) + &output[0];
let last_index = output.len() - 1;
output[last_index] = format!("{}{}", output[last_index], close);
d("render() added background", 1, Dt::Log, &options, &mut std::io::stdout());
}
let mut text = match options.env {
Env::Cli => output.join(line_break),
Env::Browser => output.join(format!("<br>{line_break}").as_str()),
};
if options.env == Env::Browser {
let color = bgcolor2hex(&options.background, &options);
let align = match options.align {
Align::Right => "right",
Align::Center => "center",
Align::Left | Align::Top | Align::Bottom => "left",
};
text = format!("<div style=\"font-family:monospace;white-space:pre;text-align:{};max-width:100%;overflow:scroll;background:{}\">{}</div>", align, color, text);
d("render() formatted for Env::Browser", 1, Dt::Log, &options, &mut std::io::stdout());
}
d(&format!("render() final output string: {:?}", text), 1, Dt::Log, &options, &mut std::io::stdout());
RenderedString {
text,
vec: output,
lines,
options,
}
}