#![allow(unused)]
pub mod base_change;
pub mod datetime;
pub mod dlog;
pub mod file;
pub mod format;
use std::fmt::Display;
use std::io::{self, Write};
use std::str::FromStr;
pub fn read_input<T>(prompt: Option<&str>) -> Result<T, String>
where
T: FromStr + Default,
<T as FromStr>::Err: Display,
{
if let Some(msg) = prompt {
print!("{}", msg);
io::stdout().flush().unwrap();
}
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.expect("Failed to read line");
let trimmed = input.trim();
if trimmed.is_empty() {
return Ok(T::default());
}
trimmed.parse().map_err(|e| format!("Parse error: {}", e))
}
pub fn __delay_ms(ms: u64) {
std::thread::sleep(std::time::Duration::from_millis(ms));
}
pub mod helpers {
use std::collections::HashMap;
use std::env;
use std::fs;
use std::io;
use std::path::PathBuf;
use crate::format::{Color, Style, Stylize};
pub fn find_cargo_toml(start_path: &str) -> io::Result<PathBuf> {
let mut path = PathBuf::from(start_path);
loop {
path = match path.parent() {
Some(parent) => parent.to_path_buf(),
None => env::current_dir()?,
};
let cargo_path = path.join("Cargo.toml");
if cargo_path.exists() {
return Ok(cargo_path);
}
if path.as_os_str().is_empty() {
return Err(io::Error::new(
io::ErrorKind::NotFound,
"Cargo.toml not found in any parent directory",
));
}
}
}
pub fn extract_app_data_with_sections<'a>(
data: &'a str,
sections: &[(&str, &[&str])],
) -> HashMap<&'a str, HashMap<&'a str, String>> {
let mut app_data = HashMap::new();
let mut current_section = "";
let mut current_key = "";
let mut multi_line_value = String::new();
for line in data.lines() {
let trimmed_line = line.trim();
if trimmed_line.is_empty() || trimmed_line.starts_with('#') {
continue;
}
let line_without_comment = trimmed_line.split('#').next().unwrap().trim();
if line_without_comment.starts_with('[') && line_without_comment.ends_with(']') {
current_section = line_without_comment.trim_matches(&['[', ']'][..]);
} else if let Some((key, value)) = line_without_comment.split_once('=') {
let key = key.trim();
if sections
.iter()
.any(|&(s, keys)| s == current_section && keys.contains(&key))
{
let value = value.trim().trim_matches('"');
current_key = key;
if value.starts_with('[') && !value.ends_with(']') {
multi_line_value = value.to_string();
} else {
app_data
.entry(current_section)
.or_insert_with(HashMap::new)
.insert(key, value.to_string());
}
}
} else if !line_without_comment.is_empty() && !multi_line_value.is_empty() {
multi_line_value.push_str(line_without_comment);
if line_without_comment.ends_with(']') {
app_data
.entry(current_section)
.or_insert_with(HashMap::new)
.insert(
current_key,
multi_line_value.trim_matches(&['[', ']'][..]).to_string(),
);
multi_line_value.clear();
}
}
}
app_data
}
pub fn print_extracted_data(
app_data: &HashMap<&str, HashMap<&str, String>>,
skip_keys: &[&str],
) {
for (section, data) in app_data {
println!("{}:", section.style(Style::Bold));
for (key, value) in data {
if !skip_keys.contains(key) {
println!("\t{key}: {}", value.style(Style::Italic).style(Style::Dim));
}
}
println!();
}
}
}
#[macro_export]
macro_rules! app_dt {
($file_path:expr $(, $($section:expr => [$($key:expr),+ $(,)?]),* $(,)?)?) => {{
use std::io::Write;
use $crate::format::*;
use $crate::helpers::{find_cargo_toml, extract_app_data_with_sections, print_extracted_data};
print!("\x1B[2J\x1B[1;1H");
let _ = std::io::stdout().flush();
let cargo_toml_path = find_cargo_toml($file_path).expect("Failed to find Cargo.toml");
let cargo_toml = std::fs::read_to_string(cargo_toml_path).expect("Failed to read Cargo.toml");
let all_data = extract_app_data_with_sections(&cargo_toml, &[
("package", &["name", "version"]),
$( $(($section, &[$($key),+])),* )?
]);
let package_data = all_data.get("package").expect("Failed to extract package data");
println!("{} v{}\n",
package_data.get("name").unwrap().color(Color::new(16, 192, 16)),
package_data.get("version").unwrap().color(Color::new(8, 64, 224)).style(Style::Italic),
);
if all_data.len() > 1 || all_data.get("package").map_or(false, |p| p.len() > 2) {
print_extracted_data(&all_data, &["name", "version"]);
}
}};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn some_useful_test() {
app_dt!(file!()); }
}