#![cfg_attr(feature = "document-features", doc = "# Features")]
#![cfg_attr(feature = "document-features", doc = document_features::document_features!())]
#![cfg_attr(feature = "nightly", feature(track_path))]
mod generator;
use generator::*;
use quote::quote_spanned;
use syn::parse::{Parse, ParseStream, Result};
use syn::{parse_macro_input, Expr, LitStr, Token};
struct Parameters {
ui: Expr,
cache: Expr,
markdown: LitStr,
}
impl Parse for Parameters {
fn parse(input: ParseStream) -> Result<Self> {
let ui: Expr = input.parse()?;
input.parse::<Token![,]>()?;
let cache: Expr = input.parse()?;
input.parse::<Token![,]>()?;
let markdown: LitStr = input.parse()?;
Ok(Parameters {
ui,
cache,
markdown,
})
}
}
fn commonmark_impl(ui: Expr, cache: Expr, text: String) -> proc_macro2::TokenStream {
let stream = CommonMarkViewerInternal::new().show(ui, cache, &text);
#[cfg(feature = "dump-macro")]
{
println!("fn main() {{");
println!("{}", stream.to_string());
println!("}}");
}
#[allow(clippy::let_and_return)]
stream
}
#[proc_macro]
pub fn commonmark(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let Parameters {
ui,
cache,
markdown,
} = parse_macro_input!(input as Parameters);
commonmark_impl(ui, cache, markdown.value()).into()
}
#[proc_macro]
pub fn commonmark_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let Parameters {
ui,
cache,
markdown,
} = parse_macro_input!(input as Parameters);
let path = markdown.value();
#[cfg(feature = "nightly")]
{
proc_macro::tracked_path::path(&path);
}
let Ok(md) = std::fs::read_to_string(path) else {
return quote_spanned!(markdown.span()=>
compile_error!("Could not find markdown file");
)
.into();
};
commonmark_impl(ui, cache, md).into()
}
fn resolve_backend_crate_import() -> proc_macro2::TokenStream {
let backend_crate = proc_macro_crate::crate_name("egui_commonmark_backend");
let main_crate = proc_macro_crate::crate_name("egui_commonmark");
if backend_crate.is_ok() {
proc_macro2::TokenStream::new()
} else if let Ok(found_crate) = main_crate {
let crate_name = match found_crate {
proc_macro_crate::FoundCrate::Itself => return proc_macro2::TokenStream::new(),
proc_macro_crate::FoundCrate::Name(name) => name,
};
let crate_name_lit = proc_macro2::Ident::new(&crate_name, proc_macro2::Span::call_site());
quote::quote!(
use #crate_name_lit::egui_commonmark_backend;
)
} else {
proc_macro2::TokenStream::new()
}
}
#[test]
fn tests() {
let t = trybuild::TestCases::new();
t.pass("tests/pass/*.rs");
t.compile_fail("tests/fail/*.rs");
}