Make comments multiline.

This commit is contained in:
Stephen Chung 2021-12-21 22:16:03 +08:00
parent f9f3615878
commit 7ff50451cc
7 changed files with 120 additions and 49 deletions

View File

@ -142,27 +142,31 @@ pub fn inner_item_attributes<T: ExportedParams>(
} }
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
pub fn doc_attribute(attrs: &mut Vec<syn::Attribute>) -> syn::Result<String> { pub fn doc_attributes(attrs: &mut Vec<syn::Attribute>) -> syn::Result<Vec<String>> {
// Find the #[doc] attribute which will turn be read for function documentation. // Find the #[doc] attribute which will turn be read for function documentation.
let mut comments = String::new(); let mut comments = Vec::new();
while let Some(index) = attrs while let Some(index) = attrs
.iter() .iter()
.position(|attr| attr.path.get_ident().map(|i| *i == "doc").unwrap_or(false)) .position(|attr| attr.path.get_ident().map(|i| *i == "doc").unwrap_or(false))
{ {
let attr = attrs.remove(index); match attrs.remove(index).parse_meta()? {
let meta = attr.parse_meta()?;
match meta {
syn::Meta::NameValue(syn::MetaNameValue { syn::Meta::NameValue(syn::MetaNameValue {
lit: syn::Lit::Str(s), lit: syn::Lit::Str(s),
.. ..
}) => { }) => {
if !comments.is_empty() { let mut line = s.value();
comments += "\n";
if line.contains('\n') {
// Must be a block comment `/** ... */`
line.insert_str(0, "/**");
line.push_str("*/");
} else {
// Single line - assume it is `///`
line.insert_str(0, "///");
} }
comments += &s.value(); comments.push(line);
} }
_ => continue, _ => continue,
} }

View File

@ -283,7 +283,7 @@ pub struct ExportedFn {
params: ExportedFnParams, params: ExportedFnParams,
cfg_attrs: Vec<syn::Attribute>, cfg_attrs: Vec<syn::Attribute>,
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
comment: String, comments: Vec<String>,
} }
impl Parse for ExportedFn { impl Parse for ExportedFn {
@ -407,7 +407,7 @@ impl Parse for ExportedFn {
params: Default::default(), params: Default::default(),
cfg_attrs, cfg_attrs,
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
comment: Default::default(), comments: Default::default(),
}) })
} }
} }
@ -508,13 +508,13 @@ impl ExportedFn {
} }
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
pub fn comment(&self) -> &str { pub fn comments(&self) -> &[String] {
&self.comment &self.comments
} }
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
pub fn set_comment(&mut self, comment: String) { pub fn set_comments(&mut self, comments: Vec<String>) {
self.comment = comment self.comments = comments
} }
pub fn set_cfg_attrs(&mut self, cfg_attrs: Vec<syn::Attribute>) { pub fn set_cfg_attrs(&mut self, cfg_attrs: Vec<syn::Attribute>) {

View File

@ -127,7 +127,7 @@ impl Parse for Module {
f.set_cfg_attrs(crate::attrs::collect_cfg_attr(&item_fn.attrs)); f.set_cfg_attrs(crate::attrs::collect_cfg_attr(&item_fn.attrs));
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
f.set_comment(crate::attrs::doc_attribute(&mut item_fn.attrs)?); f.set_comments(crate::attrs::doc_attributes(&mut item_fn.attrs)?);
Ok(f) Ok(f)
})?; })?;

View File

@ -166,14 +166,18 @@ pub fn generate_body(
); );
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
let (param_names, comment) = ( let (param_names, comments) = (
quote! { Some(#fn_token_name::PARAM_NAMES) }, quote! { Some(#fn_token_name::PARAM_NAMES) },
function.comment(), function
.comments()
.iter()
.map(|s| syn::LitStr::new(s, Span::call_site()))
.collect::<Vec<_>>(),
); );
#[cfg(not(feature = "metadata"))] #[cfg(not(feature = "metadata"))]
let (param_names, comment) = (quote! { None }, ""); let (param_names, comments) = (quote! { None }, Vec::<syn::LitStr>::new());
set_fn_statements.push(if comment.is_empty() { set_fn_statements.push(if comments.is_empty() {
syn::parse2::<syn::Stmt>(quote! { syn::parse2::<syn::Stmt>(quote! {
#(#cfg_attrs)* #(#cfg_attrs)*
m.set_fn(#fn_literal, FnNamespace::#ns_str, FnAccess::Public, m.set_fn(#fn_literal, FnNamespace::#ns_str, FnAccess::Public,
@ -181,12 +185,10 @@ pub fn generate_body(
}) })
.unwrap() .unwrap()
} else { } else {
let comment_literal = syn::LitStr::new(comment, Span::call_site());
syn::parse2::<syn::Stmt>(quote! { syn::parse2::<syn::Stmt>(quote! {
#(#cfg_attrs)* #(#cfg_attrs)*
m.set_fn_with_comment(#fn_literal, FnNamespace::#ns_str, FnAccess::Public, m.set_fn_with_comments(#fn_literal, FnNamespace::#ns_str, FnAccess::Public,
#param_names, &[#(#fn_input_types),*], #comment_literal, #fn_token_name().into()); #param_names, &[#(#fn_input_types),*], &[#(#comments),*], #fn_token_name().into());
}) })
.unwrap() .unwrap()
}); });

View File

@ -38,7 +38,7 @@ mod module_tests {
} }
#[test] #[test]
fn one_factory_fn_with_comment_module() { fn one_factory_fn_with_comments_module() {
let input_tokens: TokenStream = quote! { let input_tokens: TokenStream = quote! {
pub mod one_fn { pub mod one_fn {
/// This is a doc-comment. /// This is a doc-comment.
@ -59,7 +59,20 @@ mod module_tests {
assert!(item_mod.consts().is_empty()); assert!(item_mod.consts().is_empty());
assert_eq!(item_mod.fns().len(), 1); assert_eq!(item_mod.fns().len(), 1);
assert_eq!(item_mod.fns()[0].name().to_string(), "get_mystic_number"); assert_eq!(item_mod.fns()[0].name().to_string(), "get_mystic_number");
assert_eq!(item_mod.fns()[0].comment(), " This is a doc-comment.\n Another line.\n block doc-comment \n Final line.\n doc-comment\n in multiple lines\n "); assert_eq!(
item_mod.fns()[0]
.comments()
.iter()
.cloned()
.collect::<Vec<_>>(),
vec![
"/// This is a doc-comment.",
"/// Another line.",
"/// block doc-comment ",
"/// Final line.",
"/** doc-comment\n in multiple lines\n */"
]
);
assert_eq!(item_mod.fns()[0].arg_count(), 0); assert_eq!(item_mod.fns()[0].arg_count(), 0);
assert_eq!( assert_eq!(
item_mod.fns()[0].return_type().unwrap(), item_mod.fns()[0].return_type().unwrap(),
@ -354,7 +367,7 @@ mod generate_tests {
} }
#[test] #[test]
fn one_factory_fn_with_comment_module() { fn one_factory_fn_with_comments_module() {
let input_tokens: TokenStream = quote! { let input_tokens: TokenStream = quote! {
pub mod one_fn { pub mod one_fn {
/// This is a doc-comment. /// This is a doc-comment.
@ -387,8 +400,8 @@ mod generate_tests {
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn_with_comment("get_mystic_number", FnNamespace::Internal, FnAccess::Public, m.set_fn_with_comments("get_mystic_number", FnNamespace::Internal, FnAccess::Public,
Some(get_mystic_number_token::PARAM_NAMES), &[], " This is a doc-comment.\n Another line.\n block doc-comment \n Final line.\n doc-comment\n in multiple lines\n ", Some(get_mystic_number_token::PARAM_NAMES), &[], &["/// This is a doc-comment.","/// Another line.","/// block doc-comment ","/// Final line.","/** doc-comment\n in multiple lines\n */"],
get_mystic_number_token().into()); get_mystic_number_token().into());
if flatten {} else {} if flatten {} else {}
} }

View File

@ -55,7 +55,7 @@ pub struct FuncInfo {
pub return_type_name: Identifier, pub return_type_name: Identifier,
/// Comments. /// Comments.
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
pub comments: crate::SmartString, pub comments: Option<Box<[Box<str>]>>,
} }
impl FuncInfo { impl FuncInfo {
@ -492,10 +492,7 @@ impl Module {
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
return_type_name: self.identifiers.get("Dynamic"), return_type_name: self.identifiers.get("Dynamic"),
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
comments: fn_def comments: None,
.comments
.as_ref()
.map_or(crate::SmartString::new_const(), |v| v.join("\n").into()),
func: Into::<CallableFunction>::into(fn_def).into(), func: Into::<CallableFunction>::into(fn_def).into(),
} }
.into(), .into(),
@ -624,7 +621,7 @@ impl Module {
self.functions.contains_key(&hash_fn) self.functions.contains_key(&hash_fn)
} }
/// Update the metadata (parameter names/types and return type) of a registered function. /// _(metadata)_ Update the metadata (parameter names/types and return type) of a registered function.
/// Exported under the `metadata` feature only. /// Exported under the `metadata` feature only.
/// ///
/// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call. /// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call.
@ -659,6 +656,47 @@ impl Module {
self self
} }
/// _(metadata)_ Update the metadata (parameter names/types, return type and doc-comments) of a
/// registered function.
/// Exported under the `metadata` feature only.
///
/// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call.
///
/// ## Parameter Names and Types
///
/// Each parameter name/type pair should be a single string of the format: `var_name: type`.
///
/// ## Return Type
///
/// The _last entry_ in the list should be the _return type_ of the function. In other words,
/// the number of entries should be one larger than the number of parameters.
///
/// ## Comments
///
/// Block doc-comments should be kept in a single line.
///
/// Line doc-comments should be kept in one string slice per line without the termination line-break.
///
/// Leading white-spaces should be stripped, and each string slice always starts with the corresponding
/// doc-comment leader: `///` or `/**`.
#[cfg(feature = "metadata")]
#[inline]
pub fn update_fn_metadata_with_comments(
&mut self,
hash_fn: u64,
arg_names: &[impl AsRef<str>],
comments: &[impl AsRef<str>],
) -> &mut Self {
self.update_fn_metadata(hash_fn, arg_names);
if !comments.is_empty() {
let f = self.functions.get_mut(&hash_fn).expect("exists");
f.comments = Some(comments.iter().map(|s| s.as_ref().into()).collect());
}
self
}
/// Update the namespace of a registered function. /// Update the namespace of a registered function.
/// ///
/// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call. /// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call.
@ -759,7 +797,7 @@ impl Module {
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
return_type_name, return_type_name,
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
comments: crate::SmartString::new_const(), comments: None,
func: func.into(), func: func.into(),
} }
.into(), .into(),
@ -788,25 +826,32 @@ impl Module {
/// ///
/// The _last entry_ in the list should be the _return type_ of the function. /// The _last entry_ in the list should be the _return type_ of the function.
/// In other words, the number of entries should be one larger than the number of parameters. /// In other words, the number of entries should be one larger than the number of parameters.
///
/// ## Comments
///
/// Block doc-comments should be kept in a single line.
///
/// Line doc-comments should be kept in one string slice per line without the termination line-break.
///
/// Leading white-spaces should be stripped, and each string slice always starts with the corresponding
/// doc-comment leader: `///` or `/**`.
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
#[inline] #[inline]
pub fn set_fn_with_comment( pub fn set_fn_with_comments(
&mut self, &mut self,
name: impl AsRef<str> + Into<Identifier>, name: impl AsRef<str> + Into<Identifier>,
namespace: FnNamespace, namespace: FnNamespace,
access: FnAccess, access: FnAccess,
arg_names: Option<&[&str]>, arg_names: Option<&[&str]>,
arg_types: &[TypeId], arg_types: &[TypeId],
comment: impl Into<crate::SmartString>, comments: &[impl AsRef<str>],
func: CallableFunction, func: CallableFunction,
) -> u64 { ) -> u64 {
let hash = self.set_fn(name, namespace, access, arg_names, arg_types, func); let hash = self.set_fn(name, namespace, access, arg_names, arg_types, func);
let comment = comment.into(); if !comments.is_empty() {
if !comment.is_empty() {
let f = self.functions.get_mut(&hash).expect("exists"); let f = self.functions.get_mut(&hash).expect("exists");
f.comments = comment; f.comments = Some(comments.iter().map(|s| s.as_ref().into()).collect());
} }
hash hash
@ -845,7 +890,7 @@ impl Module {
/// ///
/// # Function Metadata /// # Function Metadata
/// ///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata. /// No metadata for the function is registered. Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata.
/// ///
/// # Example /// # Example
/// ///
@ -953,7 +998,8 @@ impl Module {
/// ///
/// # Function Metadata /// # Function Metadata
/// ///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata. /// No metadata for the function is registered.
/// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata.
/// ///
/// # Example /// # Example
/// ///
@ -990,7 +1036,8 @@ impl Module {
/// ///
/// # Function Metadata /// # Function Metadata
/// ///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata. /// No metadata for the function is registered.
/// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata.
/// ///
/// # Example /// # Example
/// ///
@ -1036,7 +1083,8 @@ impl Module {
/// ///
/// # Function Metadata /// # Function Metadata
/// ///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata. /// No metadata for the function is registered.
/// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata.
/// ///
/// # Example /// # Example
/// ///
@ -1097,7 +1145,8 @@ impl Module {
/// ///
/// # Function Metadata /// # Function Metadata
/// ///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata. /// No metadata for the function is registered.
/// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata.
/// ///
/// # Example /// # Example
/// ///
@ -1158,7 +1207,8 @@ impl Module {
/// ///
/// # Function Metadata /// # Function Metadata
/// ///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata. /// No metadata for the function is registered.
/// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata.
/// ///
/// # Example /// # Example
/// ///

View File

@ -168,7 +168,9 @@ impl<'a> From<&'a crate::module::FuncInfo> for FnMetadata<'a> {
} }
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
{ {
info.comments.split("\n").collect() info.comments
.as_ref()
.map_or_else(|| Vec::new(), |v| v.iter().map(|s| &**s).collect())
} }
}, },
} }