use std::{
io::{IsTerminal, Read},
iter::FromIterator,
};
use tabled::{
builder::Builder,
grid::{config::Borders, util::string},
row,
settings::{
style::{LineChar, Style},
Height, Padding, Shadow, Width,
},
Table,
};
fn main() {
let message = read_message();
print_table(message);
}
fn print_table(message: String) {
let main_table = create_main_table(&message);
let main_table_width = main_table.total_width();
let table_list = create_small_table_list(main_table_width);
println!("{table_list}");
println!("{main_table}");
}
fn read_message() -> String {
let mut buf = String::new();
let mut stdin = std::io::stdin();
if stdin.is_terminal() {
read_args(&mut buf);
} else {
stdin.read_to_string(&mut buf).expect("IO error");
}
buf
}
fn read_args(buf: &mut String) {
let args = std::env::args().collect::<Vec<_>>();
for (i, text) in args.iter().skip(1).enumerate() {
if i > 0 {
buf.push('\n');
}
buf.push_str(text);
}
}
fn create_small_table_list(width_available: usize) -> String {
let style1 = Style::modern();
let style2 = Style::extended();
let style3 = Style::modern()
.left('║')
.right('║')
.intersection_left('╟')
.intersection_right('╢')
.corner_top_right('╖')
.corner_top_left('╓')
.corner_bottom_right('╜')
.corner_bottom_left('╙');
let style4 = Style::modern()
.top('═')
.bottom('═')
.corner_top_right('╕')
.corner_top_left('╒')
.corner_bottom_right('╛')
.corner_bottom_left('╘')
.horizontal('═')
.intersection_left('╞')
.intersection_right('╡')
.intersection_top('╤')
.intersection_bottom('╧')
.intersection('╪');
let mut tables = [
create_small_table(Borders::from(style1)),
create_small_table(Borders::from(style2)),
create_small_table(Borders::from(style3)),
create_small_table(Borders::from(style4)),
];
const TOTAL_TABLE_WIDTH: usize = 19;
if width_available > TOTAL_TABLE_WIDTH {
let mut rest = width_available - TOTAL_TABLE_WIDTH;
while rest > 0 {
for table in &mut tables {
let current_width = table.total_width();
table.with(Width::increase(current_width + 1));
rest -= 1;
if rest == 0 {
break;
}
}
}
}
let small_table_row = row![tables[0], tables[1], tables[2], tables[3]]
.with(Style::blank())
.with(Padding::zero())
.to_string();
small_table_row
}
fn create_small_table(style: Borders<char>) -> Table {
let mut table = Builder::from_iter(vec![vec![" ", ""], vec![" ", ""]]).build();
table
.with(style)
.with(Padding::zero())
.with(Height::list([1, 0]));
table
}
fn create_main_table(message: &str) -> Table {
let (count_lines, message_width) = string::get_text_dimension(message);
let count_additional_separators = if count_lines > 2 { count_lines - 2 } else { 0 };
let left_table_space = (0..count_additional_separators)
.map(|_| " ║ \n")
.collect::<String>();
let left_table = format!(
" ╔═══╗ \n ╚═╦═╝ \n{}═╤══╩══╤\n ├──┬──┤\n └──┴──┘",
left_table_space
);
let mut message = message.to_owned();
if count_lines < 2 {
let mut i = count_lines;
while i < 2 {
message.push('\n');
i += 1;
}
}
let count_lines = count_lines.max(2);
let message = format!("{}\n{}", message, "═".repeat(message_width));
let mut table = row![left_table, message];
table
.with(Padding::zero())
.with(Style::modern().remove_vertical())
.modify((0, 0), LineChar::vertical('╞', count_lines))
.modify((0, 2), LineChar::vertical('╡', count_lines))
.with(Shadow::new(2));
table
}