tiny_tools/tiny_macros.rs
1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Serialize, Deserialize)]
4pub struct Log<F, L> {
5 pub file: F, // Source file where the log is generated
6 pub line: L, // Line number where the log is generated
7 pub time: String, // Timestamp for the log entry
8 pub msg: String, // Log message
9}
10
11// Macro to create and write log entries
12#[macro_export]
13macro_rules! json_logger {
14 ($msg:expr) => {{
15 use chrono::Local;
16 use std::fs::OpenOptions;
17 use std::io::Write;
18
19 // Get the current timestamp
20 let timestamp = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
21
22 // Create a log entry
23 let log_entry = $crate::tiny_macros::Log {
24 file: file!(),
25 line: line!(),
26 time: timestamp,
27 msg: $msg.to_string(),
28 };
29
30 // Serialize the log entry to JSON
31 let json_log = serde_json::to_string_pretty(&log_entry).unwrap();
32
33 let bin_name = env!("CARGO_PKG_NAME");
34 let log_dir = dirs::cache_dir()
35 .unwrap_or(dirs::data_dir().unwrap())
36 .join(bin_name);
37 if !log_dir.exists() {
38 std::fs::create_dir_all(&log_dir).unwrap();
39 }
40 let log_file = &log_dir.join("log.json");
41 if !log_file.exists() {
42 std::fs::write(log_file, "").unwrap();
43 }
44
45 // Define the log file path
46 let log_file_path = log_file; // Customize the log file path as needed
47
48 // Open the log file in append mode
49 let mut file = OpenOptions::new()
50 .create(true) // Create the file if it doesn't exist
51 .append(true) // Append to the file if it exists
52 .open(log_file_path)
53 .unwrap(); // Handle errors appropriately
54
55 // Write the JSON-formatted log entry to the file
56 writeln!(file, "{}", json_log).unwrap(); // Handle errors appropriately
57 }};
58}
59
60#[macro_export]
61#[cfg(feature = "debug")]
62macro_rules! dprintln {
63 ($($arg:tt)*) => (println!($($arg)*));
64}
65
66#[macro_export]
67#[cfg(not(feature = "debug"))]
68macro_rules! dprintln {
69 ($($arg:tt)*) => {};
70}
71
72#[macro_export]
73#[cfg(feature = "debug")]
74macro_rules! dprint {
75 ($($arg:tt)*) => (print!($($arg)*));
76}
77
78#[macro_export]
79#[cfg(not(feature = "debug"))]
80macro_rules! dprint {
81 ($($arg:tt)*) => {};
82}
83
84/// # verbose
85#[macro_export]
86macro_rules! verbose {
87 ($verbose_flag:expr, $($arg:tt)*) => {
88 if $verbose_flag {
89 println!($($arg)*);
90 }
91 };
92}
93
94#[macro_export]
95macro_rules! dev_debug {
96($verbose_flag:expr, $($arg:tt)*) => {
97 if $verbose_flag {
98 println!("[{}:{}] {}", file!(), line!(), format!($($arg)*));
99 }
100};
101}
102
103/// Show an error to stderr in a similar style to GNU coreutils.
104///
105/// Takes a [`format!`]-like input and prints it to stderr. The output is
106/// prepended with the current utility's name.
107#[macro_export]
108macro_rules! show_error(
109 ($($args:tt)+) => ({
110 eprint!("{}: ", env!("CARGO_PKG_NAME"));
111 eprintln!($($args)+);
112 })
113);
114
115// Prompt the user with a formatted string and returns `true` if they reply `'y'` or `'Y'`
116//
117// This macro functions accepts the same syntax as `format!`. The prompt is written to
118// `stderr`. A space is also printed at the end for nice spacing between the prompt and
119// the user input. Any input starting with `'y'` or `'Y'` is interpreted as `yes`.
120//#[macro_export]
121//macro_rules! prompt_yes(
122// ($($args:tt)+) => ({
123// use std::io::Write;
124// eprint!("roxide: ");
125// eprint!($($args)+);
126// eprint!(" ");
127// // uucore::crash_if_err!(1, std::io::stderr().flush());
128// uucore::read_yes()
129// })
130//);
131
132/// Macro to prompt the user with a message and collect input.
133/// Returns `true` if the input is "yes" or "y" (case-insensitive), otherwise `false`.
134///
135/// Example usage:
136/// ```
137/// if prompt_yes!("Do you want to continue? (yes/y):") {
138/// println!("Continuing...");
139/// } else {
140/// println!("Exiting...");
141/// }
142/// ```
143#[macro_export]
144macro_rules! prompt_yes {
145 ($($arg:tt)*) => {{
146 use std::io::{self, Write};
147 // Print the prompt and flush stdout
148 print!("{}: ", env!("CARGO_PKG_NAME"));
149 print!($($arg)*);
150 print!(" "); // Add a space after the prompt
151 io::stdout().flush().unwrap();
152
153 // Read input from stdin
154 let mut input = String::new();
155 io::stdin().read_line(&mut input).unwrap();
156
157 // Trim and check for "yes" or "y" (case-insensitive)
158 matches!(input.trim().to_lowercase().as_str(), "yes" | "y")
159 }};
160}