termo_gen/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
///! # termo_gen
///! code generator for termo terminal ui library
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
///# termo::display
/// display trait for termo makes a custom display for the struct
/// with tree like structure and colors to make it easier to read
/// example:
/// ```
/// #[termo::display]
/// pub struct DedicatedCar {
/// pub date: DateTime<Utc>,
/// pub team: String,
/// pub passengers: String,
/// pub time: DateTime<Utc>,
/// pub route: String,
/// pub car_type: String,
/// pub comments: String,
/// pub daily_rate: f64,
/// pub additional: f64,
/// pub total_rate: f64,
/// pub booking_ref: Option<String>,
/// }
/// ```
/// will output something like this when printed
/// ```
/// ╭─ DedicatedCar ─────────
/// | date: 1970-01-01T00:00:00Z
/// | team: ""
/// | passengers: ""
/// | time: 1970-01-01T00:00:00Z
/// | route: ""
/// | car_type: ""
/// | comments: ""
/// | daily_rate: 0.0
/// | additional: 0.0
/// | total_rate: 0.0
/// | booking_ref: None
/// ╰────────────────────────
///
#[proc_macro_attribute]
pub fn display(_attr: TokenStream, item: TokenStream) -> TokenStream {
let ast = parse_macro_input!(item as DeriveInput);
let name = &ast.ident;
let fields_names = match ast.data {
syn::Data::Struct(ref data_struct) => match data_struct.fields {
syn::Fields::Named(ref fields) => fields
.named
.iter()
.map(|f| f.ident.as_ref().unwrap())
.collect::<Vec<_>>(),
_ => panic!("Only named fields are supported"),
},
_ => panic!("Only structs are supported"),
};
//generate original struct definition but add derive(Debug)
let mut struct_def = quote! {
#ast
};
//generate impl Debug for struct
let mut dbg_impl = quote! {
impl std::fmt::Debug for #name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut s = String::new();
s.push_str(&format!("{}╭─{} {}{}{} ─────────\n", termo::GRAY, termo::RESET, termo::MAGENTA, stringify!(#name), termo::GRAY));
#(s.push_str(&format!("| {}{}{}{}: {}{:?}{}\n", termo::RESET, termo::YELLOW, stringify!(#fields_names), termo::RESET, termo::WHITE, self.#fields_names, termo::GRAY));)*
s.push_str(format!("╰────────────────────────{}\n", termo::RESET).as_str());
write!(f, "{}", s)
}
}
};
let output = quote! {
#struct_def
#dbg_impl
};
output.into()
}
// ╭─ {header} ──────────── __
// | ____ ___ ____ / /_____
// | / __ `__ \/ __ \/ __/ __ \
// | / / / / / / /_/ / /_/ /_/ /
// | /_/ /_/ /_/\____/\__/\____/
// |
// ╰─╮─[white] {subtitle} [/]─[yellow] {tail} ─"#;