Part of an extended cleanup effort, fluent_embed will likely get renamed to fluent_embed_derive and fluent_embed_runtime will take its place, re-exporting the macro similar to serde.
OWXLFLRMQDTXWN5QQQLJNAATWFWXIN2S4UQA2LC2A6AWX4UWM6LQC BANMRGROVYKYRJ4N2P4HSOJ2JVV6VSEB3W34BFXPOEFND5O36CGAC 2SITVDYW6KANM24QXRHVSBL6S77UHKJLOSOHSUZQBJFL5NAAGQYAC AL3CCMWZO6HUEGGNHILIQE4V3W2Z3CUOSNUTDPETCSN5IWWVITDQC KDUI7LHJRRQRFYPY7ANUNXG6XCUKQ4YYOEL5NG5Y6BRMV6GQ5M7AC SHNZZSZGIBTTD4IV5SMW5BIN5DORUWQVTVTNB5RMRD5CTFNOMJ6AC F5LG7WENUUDRSCTDMA4M6BAC5RWTGQO45C4ZEBZDX6FHCTTHBVGQC V5S5K33ALIEG5ZABUSAPO4ULHEBFDB2PLTW27A4BFS342SJG7URQC NO3PDO7PY7J3WPADNCS5VD6HKFY63E23I3SDR4DHXNVQJTG27RAAC HHJDRLLNN36UNIA7STAXEEVBCEMPJNB7SJQOS3TJLLYN4AEZ4MHQC RLX6XPNZKD6GIRLWKYXFH2RNIU4ZNXLMHXLOMID3E6H53QXXXNZQC VYPJUPPKPVSIDCQPKZE2RJLMUQDI2IYV5COBQAEXI3VF3SF4CQTAC XEEXWJLGVIPIGURSDU4ETZMGAIFTFDPECM4QWFOSRHU7GMGVOUVQC O77KA6C4UJGZXVGPEA7WCRQH6XYQJPWETSPDXI3VOKOSRQND7JEQC QFPQZR4K4UZ7R2GQZJG4NYBGVQJVL2ANIKGGTOHAMIRIBQHPSQGAC XGNME3WRU3MJDTFHUFJYARLVXWBZIH5ODBOIIFTXHNCBTZQH2R7QC UOMQT7LTURIIWHZT2ZHLCJG6XESYTN26EJC7IHRFR4PYJ355PNYAC BFL2Y7GN6NBXXNAUSD4M6T6CIVQ2OLERPE2CAFSLRF377WFFTVCQC ROSR4HD5ENPQU3HH5IVYSOA5YM72W77CHVQARSD3T67BUNYG7KZQC 56F2YE6HUZ76U4QBPUDJ2VQLJ75TQYNTVQIOX4QBOZ2H6GJKRGUQC VZYZRAO4EXCHW2LBVFG5ELSWG5SCNDREMJ6RKQ4EKQGI2T7SD3ZQC JZXXFWQKOYAFQLQZDRALXG4KGEDR7JKO3AZ5Q5X7IQTS7BCJP3QAC VNSHGQYNPGKGGPYNVP4Z2RWD7JCSDJVYAADD6UXWBYL6ZRXKLE4AC UKFEFT6LSI4K7X6UHQFZYD52DILKXMZMYSO2UYS2FCHNPXIF4BEQC WBI5HFOBBUMDSGKY2RX3YA6N7YDCJEP23JNEJ7PG5VZXHLYIRJRQC [package]name = "cli_macros"version = "0.1.0"edition = "2021"[lib]proc-macro = true[lints]workspace = true[dependencies]fluent_embed = { path = "../fluent_embed" }miette = { version = "7.2.0", features = ["fancy"] }proc-macro2 = "1.0.78"quote = "1.0.35"proc-macro-error = "1.0.4"syn = { version = "2.0.48", features = ["full", "extra-traits"] }wax = { git = "https://github.com/Finchiedev/wax" }[dev-dependencies]fluent_embed_runtime = { path = "../fluent_embed_runtime" }
//! A proc_macro shim for other crates in this workspaceuse fluent_embed::{AttributeError, FluentError, MacroError};use proc_macro::TokenStream;use proc_macro_error::{abort, emit_call_site_error, emit_error, proc_macro_error};use quote::{quote, ToTokens};use syn::parse_macro_input;fn attribute_error(error: AttributeError, derive_attribute: &syn::LitStr) {match error {AttributeError::Build(build_error) => {for location in build_error.locations() {// Create a token stream from the attribute's string literallet [proc_macro2::TokenTree::Literal(ref string_literal)] = derive_attribute.to_token_stream().into_iter().collect::<Vec<_>>()[..]else {abort!(derive_attribute, "unexpected macro attribute");};let (span_start, span_length) = location.span();let error_source = string_literal// Offset by 1 to skip the starting `"` double-quote character.subspan(span_start + 1..=span_start + span_length)// Fall back to the whole attribute if `subspan()` returns `None`// This will always happend on stable as subspan is nightly-only:// https://docs.rs/proc-macro2/latest/proc_macro2/struct.Literal.html#method.subspan.unwrap_or(derive_attribute.span());emit_error! { error_source, "invalid glob";note = location.to_string();};}}AttributeError::Walk(walk_error) => {// Generate help textlet help = if let Some(path) = walk_error.path() {let path_name = path.to_str().unwrap();// Might hit an error if file exists but insufficient permissionsmatch path.try_exists() {Ok(true) => {format!("the path `{path_name}` exists, but unable to access it")}_ => format!("the path `{path_name}` doesn't seem to exist"),}} else {String::from("no associated path")};emit_error! { derive_attribute, "error at depth {} while walking path", walk_error.depth();help = help;};}AttributeError::NoMatches {path,complete_match,} => {// Validate the assumption that the user has provided an exact pathassert!(path.exists());assert_eq!(path.to_string_lossy(), complete_match);emit_error! { derive_attribute, "cannot match against an exact path";help = "The attribute should use glob syntax to match against multiple files";note = "For example, you can:\n{}\n{}","- Match against directories: locale/**/errors.ftl","- Match against files: locale/*.ftl";};}}}fn fluent_error(error: FluentError) {// It doesn't seem like you can reference non-Rust source files// in `proc_macro::Span`, so use Miette to pretty-print our own reports.// This includes setting up a global report handler with some extra optionsmiette::set_hook(Box::new(|_| {Box::new(miette::MietteHandlerOpts::new()// Force color output, even when printing using the debug formatter.color(true).build(),)})).unwrap();eprintln!("{:?}", miette::Error::new(error));// Make sure compilation failsemit_call_site_error!("invalid Fluent source code, see above for details");}#[proc_macro_attribute]#[proc_macro_error]pub fn localize(attribute: TokenStream, item: TokenStream) -> TokenStream {let original_item = proc_macro2::TokenStream::from(item.clone());let derive_attribute: syn::LitStr = parse_macro_input!(attribute);let derive_input = parse_macro_input!(item);let implementation = match fluent_embed::localize(&derive_attribute, &derive_input) {Ok(implementation) => implementation,Err(macro_error) => {// Emit the relevant error messagesmatch macro_error {MacroError::Attribute(error) => attribute_error(error, &derive_attribute),MacroError::Fluent(error) => fluent_error(error),}// Generate a minimal `localize()` implementation so the error is self-containedlet ident = &derive_input.ident;quote! {impl #ident {fn localize(&self) -> String {unimplemented!("Encountered error in proc-macro")}}}}};quote! {#original_item#implementation}.into()}
#[proc_macro_attribute]#[proc_macro_error]pub fn localize(attribute: TokenStream, item: TokenStream) -> TokenStream {let original_item = proc_macro2::TokenStream::from(item.clone());let derive_attribute: syn::LitStr = parse_macro_input!(attribute);let derive_input = parse_macro_input!(item);let implementation = localize_impl(&derive_attribute, &derive_input).unwrap_or_else(|error| error::handle(error, &derive_attribute, &derive_input.ident));quote! {#original_item#implementation}.into()}
use super::{AttributeError, MacroError};use proc_macro_error::{abort, emit_call_site_error, emit_error};use quote::{quote, ToTokens};fn attribute(error: AttributeError, derive_attribute: &syn::LitStr) {match error {AttributeError::Build(build_error) => {for location in build_error.locations() {// Create a token stream from the attribute's string literallet [proc_macro2::TokenTree::Literal(ref string_literal)] = derive_attribute.to_token_stream().into_iter().collect::<Vec<_>>()[..]else {abort!(derive_attribute, "unexpected macro attribute");};let (span_start, span_length) = location.span();let error_source = string_literal// Offset by 1 to skip the starting `"` double-quote character.subspan(span_start + 1..=span_start + span_length)// Fall back to the whole attribute if `subspan()` returns `None`// This will always happend on stable as subspan is nightly-only:// https://docs.rs/proc-macro2/latest/proc_macro2/struct.Literal.html#method.subspan.unwrap_or(derive_attribute.span());emit_error! { error_source, "invalid glob";note = location.to_string();};}}AttributeError::Walk(walk_error) => {// Generate help textlet help = if let Some(path) = walk_error.path() {let path_name = path.to_str().unwrap();// Might hit an error if file exists but insufficient permissionsmatch path.try_exists() {Ok(true) => {format!("the path `{path_name}` exists, but unable to access it")}_ => format!("the path `{path_name}` doesn't seem to exist"),}} else {String::from("no associated path")};emit_error! { derive_attribute, "error at depth {} while walking path", walk_error.depth();help = help;};}AttributeError::NoMatches {path,complete_match,} => {// Validate the assumption that the user has provided an exact pathassert!(path.exists());assert_eq!(path.to_string_lossy(), complete_match);emit_error! { derive_attribute, "cannot match against an exact path";help = "The attribute should use glob syntax to match against multiple files";note = "For example, you can:\n{}\n{}","- Match against directories: locale/**/errors.ftl","- Match against files: locale/*.ftl";};}}}fn fluent(error: super::fluent::Error) {// It doesn't seem like you can reference non-Rust source files// in `proc_macro::Span`, so use Miette to pretty-print our own reports.// This includes setting up a global report handler with some extra optionsmiette::set_hook(Box::new(|_| {Box::new(miette::MietteHandlerOpts::new()// Force color output, even when printing using the debug formatter.color(true).build(),)})).unwrap();eprintln!("{:?}", miette::Error::new(error));// Make sure compilation failsemit_call_site_error!("invalid Fluent source code, see above for details");}pub fn handle(error: MacroError,derive_attribute: &syn::LitStr,ident: &syn::Ident,) -> proc_macro2::TokenStream {match error {MacroError::Attribute(error) => attribute(error, derive_attribute),MacroError::Fluent(error) => fluent(error),};// Generate a minimal `localize()` implementation so the error is self-containedquote! {impl #ident {fn localize(&self) -> String {unimplemented!("Encountered error in derive macro")}}}}
[[package]]name = "cli_macros"version = "0.1.0"dependencies = ["fluent_embed","fluent_embed_runtime","miette","proc-macro-error","proc-macro2","quote","syn 2.0.71","wax",]
name = "prettyplease"version = "0.2.20"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e"dependencies = ["proc-macro2","syn 2.0.71",][[package]]