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
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use rustfmt_wrapper::rustfmt;
use synoptic::languages::rust;
use synoptic::Token;
/// This macro turns rust code snippets into syntax highlighted html.
/// If you have the html feature enabled it will directly return a `yew::Html` type using a component called `RawHtml` in order to turn a string into html.
/// This is needed because yew does not yet support turning a string into html
/// In order for this to work, this component needs to be created as follows:
///
/// ```
/// use yew::{function_component, Html, Properties};
/// #[derive(Properties, PartialEq)]
/// pub struct Props {
/// pub html: String,
/// }
/// #[function_component(RawHtml)]
/// pub fn raw_html(props: &Props) -> Html {
/// let div = web_sys::window()
/// .unwrap()
/// .document()
/// .unwrap()
/// .create_element("div")
/// .unwrap();
/// div.set_inner_html(&props.html.clone());
///
/// Html::VRef(div.into())
/// }
/// ```
/// Without this feature, it will just return a string of html.
/// # Panics
///
/// Panics at compile time if code is invalid.
#[proc_macro]
pub fn generate_snippet(item: TokenStream) -> TokenStream {
let code = rustfmt(item).unwrap();
let mut result = String::from(
r#"<div style="background: #181818; overflow:auto;width:auto;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%">"#,
);
let rust = rust();
let highlighting = rust.run(code.trim());
for (c, row) in highlighting.iter().enumerate() {
// Print line number (with padding)
result.push_str(format!("{: >2} ", c).as_str());
// For each token within each row
for tok in row {
// Handle the tokens
match tok {
// Handle the start token (start foreground colour)
Token::Start(kind) => {
result.push_str("<span style=\"");
match kind.as_str() {
"keyword" => result.push_str("color: #ba8baf;\">"),
"struct" => result.push_str("color: #f7ca88;\">"),
"boolean" | "number" | "global" => result.push_str("color: #dc9656;\">"),
"operator" => result.push_str("color: #d8d8d8;\">"),
"comment" | "reference" => result.push_str("color: #585858;\">"),
"string" | "character" => result.push_str("color: #a1b56c;\">"),
"function" | "macro" => result.push_str("color: #7cafc2;\">"),
"regex" | "symbol" => result.push_str("color: #86c1b9;\">"),
token => println!("unknow token: {}", token),
}
}
// Handle a text token (print out the contents)
Token::Text(txt) => result.push_str(txt),
// Handle an end token (reset foreground colour)
Token::End(_) => result.push_str("</span>"),
}
}
result.push('\n');
}
result.push_str("</pre></div>");
#[cfg(feature = "html")]
return quote! {
html! {
<RawHtml html={#result} />
}
}
.into();
quote! {
#result
}
.into()
}