mod colors;
mod emojis;
use regex::Regex;
use regex::escape;
use std::io::{self, Write};
pub fn print<T: AsRef<[U]>, U: std::fmt::Debug + std::fmt::Display>(data: T) {
let slice: &[U] = data.as_ref();
for item in slice {
print!("{}", item);
io::stdout().flush().unwrap();
}
}
fn replace_emoji_shortcodes(text: &str) -> String {
let emoji_map = emojis::emoji_shortcodes();
let mut replaced_text = String::from(text);
for (shortcode, emoji) in emoji_map.iter() {
let regex_str = format!(":{}:", escape(shortcode));
let regex = Regex::new(®ex_str).unwrap();
replaced_text = regex.replace_all(&replaced_text, *emoji).to_string();
}
replaced_text
}
pub fn text(usertext: &str, format: &str) -> String{
if format.is_empty(){
let retstr = replace_emoji_shortcodes(usertext);
return retstr;
}
let escape = "\x1b";
let end_seq = "\x1b[0m";
let mut all_effects = String::from("");
let ansi_codes = colors::ansi_color_codes();
let parts: Vec<&str> = format.split_whitespace().collect();
for part in parts{
let part_all: Vec<&str> = part.split(':').collect(); let command = part_all[0]; let val = part_all[1]; if command == "fg"{
if val.starts_with("rgb("){
let trimmed_start = val.trim_start_matches("rgb(");
let trimmed_end = trimmed_start.trim_end_matches(")");
let rgb: Vec<&str> = trimmed_end.split(',').collect();
let rgb_formatted = format!("{}[38;2;{};{};{}m", escape, rgb[0], rgb[1], rgb[2]);
all_effects.push_str(&rgb_formatted);
} else {
let fg_code = ansi_codes.get(&val).expect("Cannot find color name").to_string();
let fg_formatted = format!("{}[38;5;{}m", escape, fg_code);
all_effects.push_str(&fg_formatted);
}
} else if command == "bg"{
if val.starts_with("rgb("){
let trimmed_start = val.trim_start_matches("rgb(");
let trimmed_end = trimmed_start.trim_end_matches(')');
let rgb: Vec<&str> = trimmed_end.split(',').collect();
let rgb_formatted = format!("{}[48;2;{};{};{}m", escape, rgb[0], rgb[1], rgb[2]);
all_effects.push_str(&rgb_formatted);
} else {
let bg_code = ansi_codes.get(&val).expect("Cannot find color name").to_string();
let bg_formatted = format!("{}[48;5;{}m", escape, bg_code);
all_effects.push_str(&bg_formatted);
}
} else if command == "eff"{
let user_effects: Vec<&str> = val.split(',').collect();
for effect in user_effects{
match effect {
"i" => {
let e = format!("{}[3m", escape);
all_effects.push_str(&e);
},
"blink" => {
let e = format!("{}[5m", escape);
all_effects.push_str(&e);
},
"u" => {
let e = format!("{}[4m", escape);
all_effects.push_str(&e);
},
"b" => {
let e = format!("{}[1m", escape);
all_effects.push_str(&e);
},
"s" => {
let e = format!("{}[9m", escape);
all_effects.push_str(&e);
},
"d" => {
let e = format!("{}[2m", escape);
all_effects.push_str(&e);
},
"r" => {
let e = format!("{}[7m", escape);
all_effects.push_str(&e);
},
"hc" => {
let e = format!("{}[?25l", escape);
all_effects.push_str(&e);
},
"sc" => {
let e = format!("{}[?25h", escape);
all_effects.push_str(&e);
},
&_ => {
all_effects.push_str("");
}
}
}
}
}
let usert = replace_emoji_shortcodes(usertext);
let to_ret = format!("{}{}{}", all_effects, usert, end_seq);
to_ret
}
use std::iter::Iterator;
pub struct MyRange<'a>{
start: i32,
end: i32,
description: &'a str,
bar_width: i32,
display: &'a str,
elapsed_time_f: String
}
impl Iterator for MyRange<'_>{
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
if self.start <= self.end {
let current = self.start;
self.start += 1;
Some(current)
} else {
None
}
}
}
impl Drop for MyRange<'_>{
fn drop(&mut self) {
print([
text("\r ", ""),
text(self.description, ""),
text(" ",""),
text(&self.display.repeat(self.bar_width.try_into().unwrap()), "fg:green"),
text(" 100% ", "fg:magenta"),
text(&self.elapsed_time_f, "fg:orange1"),
text("\n",""),
]);
}
}
fn create_range<'a>(start: i32, end: i32, description: &'a str, bar_width: i32, display: &'a str, elapsed_time_f: String) -> MyRange<'a> {
MyRange { start, end, description, bar_width, display, elapsed_time_f }
}
use std::time::{Duration, Instant};
fn format_duration(duration: Duration) -> String {
let hours = duration.as_secs() / 3600;
let minutes = (duration.as_secs() % 3600) / 60;
let seconds = duration.as_secs() % 60;
format!("{:02}:{:02}:{:02}", hours, minutes, seconds)
}
pub fn track(step: i32, description: &str) -> MyRange<'_>{
let len_itr = step;let bar_width = 40;
let display = "━";
let incr = bar_width/len_itr as i32;
let mut step = 0;
let start_time = Instant::now();
for _item in 1..len_itr{
let perc = (step as f32 /bar_width as f32) * 100.0;
let elapsed_time = start_time.elapsed();
let elapsed_time_f = format!("{} ", format_duration(elapsed_time));
print([
text("\r ", "eff:hc"),
text(description, ""),
text(" ",""),
text(&display.repeat(step.try_into().unwrap()), "fg:deep_pink3"),
text(&display.repeat((bar_width-step).try_into().unwrap()), "fg:black"),
text(&format!(" {}% ", perc as i32), "fg:magenta"),
text(&elapsed_time_f, "fg:steel_blue eff:sc")
]);
step = step + incr;
}
let elapsed_time = start_time.elapsed();
let elapsed_time_f = format_duration(elapsed_time);
return create_range(1, len_itr, description, bar_width, display, elapsed_time_f);
}