Merge multiple doc-comment lines into one.

This commit is contained in:
Stephen Chung 2022-12-01 14:35:45 +08:00
parent 28640a6fe4
commit 0c4935febb
8 changed files with 120 additions and 91 deletions

View File

@ -43,6 +43,7 @@ Enhancements
* `FuncArgs` is also implemented for arrays. * `FuncArgs` is also implemented for arrays.
* `Engine::set_XXX` API can now be chained. * `Engine::set_XXX` API can now be chained.
* `EvalContext::scope_mut` now returns `&mut Scope` instead of `&mut &mut Scope`. * `EvalContext::scope_mut` now returns `&mut Scope` instead of `&mut &mut Scope`.
* Line-style doc-comments are now merged into a single string to avoid creating many strings. Block-style doc-comments continue to be independent strings.
Version 1.11.0 Version 1.11.0

View File

@ -145,6 +145,7 @@ pub fn inner_item_attributes<T: ExportedParams>(
pub fn doc_attributes(attrs: &[syn::Attribute]) -> syn::Result<Vec<String>> { pub fn doc_attributes(attrs: &[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 = Vec::new(); let mut comments = Vec::new();
let mut buf = String::new();
for attr in attrs { for attr in attrs {
if let Some(i) = attr.path.get_ident() { if let Some(i) = attr.path.get_ident() {
@ -158,19 +159,30 @@ pub fn doc_attributes(attrs: &[syn::Attribute]) -> syn::Result<Vec<String>> {
if line.contains('\n') { if line.contains('\n') {
// Must be a block comment `/** ... */` // Must be a block comment `/** ... */`
if !buf.is_empty() {
comments.push(buf.clone());
buf.clear();
}
line.insert_str(0, "/**"); line.insert_str(0, "/**");
line.push_str("*/"); line.push_str("*/");
comments.push(line);
} else { } else {
// Single line - assume it is `///` // Single line - assume it is `///`
line.insert_str(0, "///"); if !buf.is_empty() {
buf.push('\n');
}
buf.push_str("///");
buf.push_str(&line);
} }
comments.push(line);
} }
} }
} }
} }
if !buf.is_empty() {
comments.push(buf);
}
Ok(comments) Ok(comments)
} }

View File

@ -230,7 +230,7 @@ pub fn generate_body(
syn::parse2::<syn::Stmt>(quote! { syn::parse2::<syn::Stmt>(quote! {
#(#cfg_attrs)* #(#cfg_attrs)*
m.set_fn_with_comments(#fn_literal, FnNamespace::#ns_str, FnAccess::Public, m.set_fn_with_comments(#fn_literal, FnNamespace::#ns_str, FnAccess::Public,
#param_names, &[#(#fn_input_types),*], &[#(#comments),*], #fn_token_name().into()); #param_names, [#(#fn_input_types),*], [#(#comments),*], #fn_token_name().into());
}) })
.unwrap() .unwrap()
}); });

View File

@ -92,10 +92,11 @@ mod module_tests {
.cloned() .cloned()
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
vec![ vec![
"/// This is a doc-comment.", "\
"/// Another line.", /// This is a doc-comment.\n\
"/// block doc-comment ", /// Another line.\n\
"/// Final line.", /// block doc-comment \n\
/// Final line.",
"/** doc-comment\n in multiple lines\n */" "/** doc-comment\n in multiple lines\n */"
] ]
); );
@ -444,11 +445,8 @@ mod generate_tests {
#[doc(hidden)] #[doc(hidden)]
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_comments("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), &[], &[ Some(get_mystic_number_token::PARAM_NAMES), [], [
"/// This is a doc-comment.", "/// This is a doc-comment.\n/// Another line.\n/// block doc-comment \n/// Final line.",
"/// Another line.",
"/// block doc-comment ",
"/// Final line.",
"/** doc-comment\n in multiple lines\n */" "/** 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

@ -49,10 +49,12 @@ pub struct ScriptFnDef {
/// ///
/// Block doc-comments are kept in a single string slice with line-breaks within. /// Block doc-comments are kept in a single string slice with line-breaks within.
/// ///
/// Line doc-comments are kept in one string slice per line without the termination line-break. /// Line doc-comments are merged, with line-breaks, into a single string slice without a termination line-break.
/// ///
/// Leading white-spaces are stripped, and each string slice always starts with the /// Leading white-spaces are stripped, and each string slice always starts with the
/// corresponding doc-comment leader: `///` or `/**`. /// corresponding doc-comment leader: `///` or `/**`.
///
/// Each line in non-block doc-comments starts with `///`.
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
pub comments: Box<[Box<str>]>, pub comments: Box<[Box<str>]>,
} }
@ -98,10 +100,12 @@ pub struct ScriptFnMetadata<'a> {
/// ///
/// Block doc-comments are kept in a single string slice with line-breaks within. /// Block doc-comments are kept in a single string slice with line-breaks within.
/// ///
/// Line doc-comments are kept in one string slice per line without the termination line-break. /// Line doc-comments are merged, with line-breaks, into a single string slice without a termination line-break.
/// ///
/// Leading white-spaces are stripped, and each string slice always starts with the /// Leading white-spaces are stripped, and each string slice always starts with the
/// corresponding doc-comment leader: `///` or `/**`. /// corresponding doc-comment leader: `///` or `/**`.
///
/// Each line in non-block doc-comments starts with `///`.
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
pub comments: Vec<&'a str>, pub comments: Vec<&'a str>,
} }

View File

@ -882,13 +882,10 @@ impl Module {
pub fn update_fn_metadata<S: AsRef<str>>( pub fn update_fn_metadata<S: AsRef<str>>(
&mut self, &mut self,
hash_fn: u64, hash_fn: u64,
arg_names: impl AsRef<[S]>, arg_names: impl IntoIterator<Item = S>,
) -> &mut Self { ) -> &mut Self {
let mut param_names: StaticVec<_> = arg_names let mut param_names: StaticVec<_> =
.as_ref() arg_names.into_iter().map(|s| s.as_ref().into()).collect();
.iter()
.map(|s| s.as_ref().into())
.collect();
if let Some(f) = self.functions.as_mut().and_then(|m| m.get_mut(&hash_fn)) { if let Some(f) = self.functions.as_mut().and_then(|m| m.get_mut(&hash_fn)) {
let (param_names, return_type_name) = if param_names.len() > f.metadata.num_params { let (param_names, return_type_name) = if param_names.len() > f.metadata.num_params {
@ -920,32 +917,30 @@ impl Module {
/// ///
/// ## Comments /// ## Comments
/// ///
/// Block doc-comments should be kept in a single line. /// Block doc-comments should be kept in a separate string slice.
/// ///
/// Line doc-comments should be kept in one string slice per line without the termination line-break. /// Line doc-comments should be merged, with line-breaks, into a single string slice without a final termination line-break.
/// ///
/// Leading white-spaces should be stripped, and each string slice always starts with the corresponding /// Leading white-spaces should be stripped, and each string slice always starts with the corresponding
/// doc-comment leader: `///` or `/**`. /// doc-comment leader: `///` or `/**`.
///
/// Each line in non-block doc-comments should start with `///`.
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
#[inline] #[inline]
pub fn update_fn_metadata_with_comments<A: AsRef<str>, C: AsRef<str>>( pub fn update_fn_metadata_with_comments<A: AsRef<str>, C: AsRef<str>>(
&mut self, &mut self,
hash_fn: u64, hash_fn: u64,
arg_names: impl AsRef<[A]>, arg_names: impl IntoIterator<Item = A>,
comments: impl AsRef<[C]>, comments: impl IntoIterator<Item = C>,
) -> &mut Self { ) -> &mut Self {
self.update_fn_metadata(hash_fn, arg_names); self.update_fn_metadata(hash_fn, arg_names);
let comments = comments.as_ref(); self.functions
.as_mut()
if !comments.is_empty() { .and_then(|m| m.get_mut(&hash_fn))
let f = self .unwrap()
.functions .metadata
.as_mut() .comments = comments.into_iter().map(|s| s.as_ref().into()).collect();
.and_then(|m| m.get_mut(&hash_fn))
.unwrap();
f.metadata.comments = comments.iter().map(|s| s.as_ref().into()).collect();
}
self self
} }
@ -1099,12 +1094,14 @@ impl Module {
/// ///
/// ## Comments /// ## Comments
/// ///
/// Block doc-comments should be kept in a single line. /// Block doc-comments should be kept in a separate string slice.
/// ///
/// Line doc-comments should be kept in one string slice per line without the termination line-break. /// Line doc-comments should be merged, with line-breaks, into a single string slice without a final termination line-break.
/// ///
/// Leading white-spaces should be stripped, and each string slice always starts with the corresponding /// Leading white-spaces should be stripped, and each string slice always starts with the corresponding
/// doc-comment leader: `///` or `/**`. /// doc-comment leader: `///` or `/**`.
///
/// Each line in non-block doc-comments should start with `///`.
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
#[inline] #[inline]
pub fn set_fn_with_comments<S: AsRef<str>>( pub fn set_fn_with_comments<S: AsRef<str>>(

View File

@ -235,18 +235,18 @@ macro_rules! reg_range {
concat!("from: ", stringify!($y)), concat!("from: ", stringify!($y)),
concat!("to: ", stringify!($y)), concat!("to: ", stringify!($y)),
concat!("Iterator<", stringify!($y), ">"), concat!("Iterator<", stringify!($y), ">"),
], [ ], ["\
"/// Return an iterator over the exclusive range of `from..to`.", /// Return an iterator over the exclusive range of `from..to`.\n\
"/// The value `to` is never included.", /// The value `to` is never included.\n\
"///", ///\n\
"/// # Example", /// # Example\n\
"///", ///\n\
"/// ```rhai", /// ```rhai\n\
"/// // prints all values from 8 to 17", /// // prints all values from 8 to 17\n\
"/// for n in range(8, 18) {", /// for n in range(8, 18) {\n\
"/// print(n);", /// print(n);\n\
"/// }", /// }\n\
"/// ```" /// ```"
]); ]);
$lib.set_iterator::<RangeInclusive<$y>>(); $lib.set_iterator::<RangeInclusive<$y>>();
@ -269,27 +269,27 @@ macro_rules! reg_range {
concat!("to: ", stringify!($y)), concat!("to: ", stringify!($y)),
concat!("step: ", stringify!($y)), concat!("step: ", stringify!($y)),
concat!("Iterator<", stringify!($y), ">") concat!("Iterator<", stringify!($y), ">")
], [ ], ["\
"/// Return an iterator over the exclusive range of `from..to`, each iteration increasing by `step`.", /// Return an iterator over the exclusive range of `from..to`, each iteration increasing by `step`.\n\
"/// The value `to` is never included.", /// The value `to` is never included.\n\
"///", ///\n\
"/// If `from` > `to` and `step` < 0, iteration goes backwards.", /// If `from` > `to` and `step` < 0, iteration goes backwards.\n\
"///", ///\n\
"/// If `from` > `to` and `step` > 0 or `from` < `to` and `step` < 0, an empty iterator is returned.", /// If `from` > `to` and `step` > 0 or `from` < `to` and `step` < 0, an empty iterator is returned.\n\
"///", ///\n\
"/// # Example", /// # Example\n\
"///", ///\n\
"/// ```rhai", /// ```rhai\n\
"/// // prints all values from 8 to 17 in steps of 3", /// // prints all values from 8 to 17 in steps of 3\n\
"/// for n in range(8, 18, 3) {", /// for n in range(8, 18, 3) {\n\
"/// print(n);", /// print(n);\n\
"/// }", /// }\n\
"///", ///\n\
"/// // prints all values down from 18 to 9 in steps of -3", /// // prints all values down from 18 to 9 in steps of -3\n\
"/// for n in range(18, 8, -3) {", /// for n in range(18, 8, -3) {\n\
"/// print(n);", /// print(n);\n\
"/// }", /// }\n\
"/// ```" /// ```"
]); ]);
let _hash = $lib.set_native_fn($x, |range: std::ops::Range<$y>, step: $y| StepRange::new(range.start, range.end, step, $add)); let _hash = $lib.set_native_fn($x, |range: std::ops::Range<$y>, step: $y| StepRange::new(range.start, range.end, step, $add));
@ -299,26 +299,26 @@ macro_rules! reg_range {
concat!("range: Range<", stringify!($y), ">"), concat!("range: Range<", stringify!($y), ">"),
concat!("step: ", stringify!($y)), concat!("step: ", stringify!($y)),
concat!("Iterator<", stringify!($y), ">") concat!("Iterator<", stringify!($y), ">")
], [ ], ["\
"/// Return an iterator over an exclusive range, each iteration increasing by `step`.", /// Return an iterator over an exclusive range, each iteration increasing by `step`.\n\
"///", ///\n\
"/// If `range` is reversed and `step` < 0, iteration goes backwards.", /// If `range` is reversed and `step` < 0, iteration goes backwards.\n\
"///", ///\n\
"/// Otherwise, if `range` is empty, an empty iterator is returned.", /// Otherwise, if `range` is empty, an empty iterator is returned.\n\
"///", ///\n\
"/// # Example", /// # Example\n\
"///", ///\n\
"/// ```rhai", /// ```rhai\n\
"/// // prints all values from 8 to 17 in steps of 3", /// // prints all values from 8 to 17 in steps of 3\n\
"/// for n in range(8..18, 3) {", /// for n in range(8..18, 3) {\n\
"/// print(n);", /// print(n);\n\
"/// }", /// }\n\
"///", ///\n\
"/// // prints all values down from 18 to 9 in steps of -3", /// // prints all values down from 18 to 9 in steps of -3\n\
"/// for n in range(18..8, -3) {", /// for n in range(18..8, -3) {\n\
"/// print(n);", /// print(n);\n\
"/// }", /// }\n\
"/// ```" /// ```"
]); ]);
)* )*
}; };

View File

@ -3208,6 +3208,7 @@ impl Engine {
let comments = { let comments = {
let mut comments = StaticVec::<SmartString>::new(); let mut comments = StaticVec::<SmartString>::new();
let mut comments_pos = Position::NONE; let mut comments_pos = Position::NONE;
let mut buf = SmartString::new_const();
// Handle doc-comments. // Handle doc-comments.
while let (Token::Comment(ref comment), pos) = input.peek().expect(NEVER_ENDS) { while let (Token::Comment(ref comment), pos) = input.peek().expect(NEVER_ENDS) {
@ -3225,7 +3226,19 @@ impl Engine {
match input.next().expect(NEVER_ENDS).0 { match input.next().expect(NEVER_ENDS).0 {
Token::Comment(comment) => { Token::Comment(comment) => {
comments.push(*comment); if comment.contains('\n') {
// Assume block comment
if !buf.is_empty() {
comments.push(buf.clone());
buf.clear();
}
comments.push(*comment);
} else {
if !buf.is_empty() {
buf.push('\n');
}
buf.push_str(&comment);
}
match input.peek().expect(NEVER_ENDS) { match input.peek().expect(NEVER_ENDS) {
(Token::Fn | Token::Private, ..) => break, (Token::Fn | Token::Private, ..) => break,
@ -3237,6 +3250,10 @@ impl Engine {
} }
} }
if !buf.is_empty() {
comments.push(buf);
}
comments comments
}; };