summaryrefslogtreecommitdiff
path: root/macros
diff options
context:
space:
mode:
Diffstat (limited to 'macros')
-rw-r--r--macros/src/element.rs7
-rw-r--r--macros/src/func.rs6
-rw-r--r--macros/src/util.rs19
3 files changed, 28 insertions, 4 deletions
diff --git a/macros/src/element.rs b/macros/src/element.rs
index 403af103..61830939 100644
--- a/macros/src/element.rs
+++ b/macros/src/element.rs
@@ -10,6 +10,7 @@ struct Elem {
name: String,
display: String,
category: String,
+ keywords: Option<String>,
docs: String,
vis: syn::Visibility,
ident: Ident,
@@ -126,6 +127,7 @@ fn prepare(stream: TokenStream, body: &syn::ItemStruct) -> Result<Elem> {
let mut attrs = body.attrs.clone();
let docs = documentation(&attrs);
let mut lines = docs.split('\n').collect();
+ let keywords = meta_line(&mut lines, "Keywords").ok().map(Into::into);
let category = meta_line(&mut lines, "Category")?.into();
let display = meta_line(&mut lines, "Display")?.into();
let docs = lines.join("\n").trim().into();
@@ -134,6 +136,7 @@ fn prepare(stream: TokenStream, body: &syn::ItemStruct) -> Result<Elem> {
name: body.ident.to_string().trim_end_matches("Elem").to_lowercase(),
display,
category,
+ keywords,
docs,
vis: body.vis.clone(),
ident: body.ident.clone(),
@@ -332,7 +335,7 @@ fn create_set_field_method(field: &Field) -> TokenStream {
/// Create the element's `Pack` implementation.
fn create_pack_impl(element: &Elem) -> TokenStream {
- let Elem { ident, name, display, category, docs, .. } = element;
+ let Elem { ident, name, display, keywords, category, docs, .. } = element;
let vtable_func = create_vtable_func(element);
let infos = element
.fields
@@ -340,6 +343,7 @@ fn create_pack_impl(element: &Elem) -> TokenStream {
.filter(|field| !field.internal && !field.synthesized)
.map(create_param_info);
let scope = create_scope_builder(element.scope.as_ref());
+ let keywords = quote_option(keywords);
quote! {
impl ::typst::model::Element for #ident {
fn pack(self) -> ::typst::model::Content {
@@ -362,6 +366,7 @@ fn create_pack_impl(element: &Elem) -> TokenStream {
info: ::typst::eval::Lazy::new(|| typst::eval::FuncInfo {
name: #name,
display: #display,
+ keywords: #keywords,
docs: #docs,
params: ::std::vec![#(#infos),*],
returns: ::std::vec!["content"],
diff --git a/macros/src/func.rs b/macros/src/func.rs
index f3de6822..2d38c01a 100644
--- a/macros/src/func.rs
+++ b/macros/src/func.rs
@@ -12,6 +12,7 @@ struct Func {
name: String,
display: String,
category: String,
+ keywords: Option<String>,
docs: String,
vis: syn::Visibility,
ident: Ident,
@@ -80,6 +81,7 @@ fn prepare(item: &syn::ItemFn) -> Result<Func> {
.split(" or ")
.map(Into::into)
.collect();
+ let keywords = meta_line(&mut lines, "Keywords").ok().map(Into::into);
let category = meta_line(&mut lines, "Category")?.into();
let display = meta_line(&mut lines, "Display")?.into();
let docs = lines.join("\n").trim().into();
@@ -88,6 +90,7 @@ fn prepare(item: &syn::ItemFn) -> Result<Func> {
name: sig.ident.to_string().replace('_', ""),
display,
category,
+ keywords,
docs,
vis: item.vis.clone(),
ident: sig.ident.clone(),
@@ -105,6 +108,7 @@ fn create(func: &Func) -> TokenStream {
let Func {
name,
display,
+ keywords,
category,
docs,
vis,
@@ -117,6 +121,7 @@ fn create(func: &Func) -> TokenStream {
let handlers = params.iter().filter(|param| !param.external).map(create_param_parser);
let params = params.iter().map(create_param_info);
let scope = create_scope_builder(func.scope.as_ref());
+ let keywords = quote_option(keywords);
quote! {
#[doc = #docs]
#vis fn #ident() -> &'static ::typst::eval::NativeFunc {
@@ -129,6 +134,7 @@ fn create(func: &Func) -> TokenStream {
info: ::typst::eval::Lazy::new(|| typst::eval::FuncInfo {
name: #name,
display: #display,
+ keywords: #keywords,
docs: #docs,
params: ::std::vec![#(#params),*],
returns: ::std::vec![#(#returns),*],
diff --git a/macros/src/util.rs b/macros/src/util.rs
index 6b683e5d..2e12ef17 100644
--- a/macros/src/util.rs
+++ b/macros/src/util.rs
@@ -1,4 +1,5 @@
use heck::ToKebabCase;
+use quote::ToTokens;
use super::*;
@@ -104,13 +105,16 @@ pub fn documentation(attrs: &[syn::Attribute]) -> String {
/// Extract a line of metadata from documentation.
pub fn meta_line<'a>(lines: &mut Vec<&'a str>, key: &str) -> Result<&'a str> {
- match lines.pop().and_then(|line| line.strip_prefix(&format!("{key}:"))) {
- Some(value) => Ok(value.trim()),
+ match lines.last().and_then(|line| line.strip_prefix(&format!("{key}:"))) {
+ Some(value) => {
+ lines.pop();
+ Ok(value.trim())
+ }
None => bail!(callsite, "missing metadata key: {}", key),
}
}
-/// Creates a block responsible for building a Scope.
+/// Creates a block responsible for building a `Scope`.
pub fn create_scope_builder(scope_block: Option<&BlockWithReturn>) -> TokenStream {
if let Some(BlockWithReturn { prefix, expr }) = scope_block {
quote! { {
@@ -122,3 +126,12 @@ pub fn create_scope_builder(scope_block: Option<&BlockWithReturn>) -> TokenStrea
quote! { ::typst::eval::Scope::new() }
}
}
+
+/// Quotes an option literally.
+pub fn quote_option<T: ToTokens>(option: &Option<T>) -> TokenStream {
+ if let Some(value) = option {
+ quote! { Some(#value) }
+ } else {
+ quote! { None }
+ }
+}