use colored::{ColoredString, Colorize};
use core::fmt;
use std::{env, fmt::Display};
use crate::{
convert::{
ConversionError, ConversionOutput, ConversionResult, InputConverterType,
OutputConverterType,
},
opts::OptsBuildError,
};
pub trait ColorPalette {
fn format_heading(&self) -> ColoredString;
fn format_heading_nobold(&self) -> ColoredString;
fn format_subheading(&self) -> ColoredString;
fn format_binary(&self) -> ColoredString;
fn format_value(&self) -> ColoredString;
fn format_error(&self) -> ColoredString;
}
impl<'a> ColorPalette for &'a str {
fn format_heading(&self) -> ColoredString {
self.bold().green()
}
fn format_heading_nobold(&self) -> ColoredString {
self.green()
}
fn format_subheading(&self) -> ColoredString {
self.normal()
}
fn format_binary(&self) -> ColoredString {
self.bold().bright_white()
}
fn format_value(&self) -> ColoredString {
self.blue().bold()
}
fn format_error(&self) -> ColoredString {
self.red().bold()
}
}
pub fn usage() -> String {
let bin = env::args().next().unwrap();
let mut res = String::new();
res += &format!(
"{} {} [-h] [<input converter>] <value> [<output converters>]",
"Usage:".format_heading(),
bin
);
res
}
pub fn version() -> String {
let mut res = String::new();
res += &format!(
"{} v{}",
"baseic".format_binary(),
env!("CARGO_PKG_VERSION"),
);
res
}
pub fn help() -> String {
let bin = env::args().next().unwrap();
let mut res = String::new();
res += &format!(
"{} v{}\n",
"baseic".format_binary(),
env!("CARGO_PKG_VERSION"),
);
res += &format!("\n{}\n", usage());
res += &format!("\n{}\n", "Options:".format_heading());
res += &format!(" -h: display this message\n");
res += &format!("\n{}\n", "Input converters:".format_heading());
res += &format!(" DEC: decimal\n");
res += &format!(" BIN: binary\n");
res += &format!(" HEX: hexadecimal\n");
res += &format!(" OCT: octal\n");
res += &format!(" ASCII: ascii character\n");
res += &format!("\n{}\n", "Output converters:".format_heading());
res += &format!(" DEC: decimal\n");
res += &format!(" BIN: binary\n");
res += &format!(" HEX: hexadecimal\n");
res += &format!(" OCT: octal\n");
res += &format!(" ASCII: ascii character\n");
res += &format!("\n{} {} dec 1234 bin hex", "Example:".format_heading(), bin);
res
}
impl<'a> Display for OptsBuildError<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Args(err) => {
write!(f, "{}\n", err)?;
write!(f, "{}", usage())
}
Self::Config(err) => write!(
f,
"invalid configuration in config file:\n{}",
err.to_string()
),
}
}
}
impl Display for ConversionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self {
ConversionError::NoResults => {
write!(f, "no results")
}
}
}
}
impl Display for ConversionOutput {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (inconv, conv_res) in &self.inner {
let inconv_str: &str = &inconv.to_string();
write!(
f,
"{} {}{}\n",
"from".format_heading_nobold(),
inconv_str.format_heading(),
":".format_heading()
)?;
conv_res.fmt(f)?;
}
Ok(())
}
}
impl Display for ConversionResult {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let max_outconv_len = OutputConverterType::max_str_len();
for (outconv, val) in &self.inner {
let outconv: &str = &right_align(&outconv.to_string(), max_outconv_len);
let val: &str = &val;
write!(
f,
" {}{} {}\n",
outconv.format_subheading(),
":".format_subheading(),
val.format_value()
)?;
}
Ok(())
}
}
impl ToString for InputConverterType {
fn to_string(&self) -> String {
match self {
InputConverterType::DEC => {
format!("decimal")
}
InputConverterType::BIN => {
format!("binary")
}
InputConverterType::HEX => {
format!("hexadecimal")
}
InputConverterType::OCT => {
format!("octal")
}
InputConverterType::ASCII => {
format!("ascii")
}
}
}
}
impl ToString for OutputConverterType {
fn to_string(&self) -> String {
match self {
OutputConverterType::DEC => {
format!("decimal")
}
OutputConverterType::BIN => {
format!("binary")
}
OutputConverterType::HEX => {
format!("hexadecimal")
}
OutputConverterType::OCT => {
format!("octal")
}
OutputConverterType::ASCII => {
format!("ascii")
}
}
}
}
fn right_align(string: &str, size: usize) -> String {
let outstr: String = (string.len()..size).map(|_| ' ').collect();
outstr + string
}