-
-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Detect padding in doc comments #204
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -111,20 +111,40 @@ impl CommentVariant { | |
} | ||
} | ||
|
||
/// Track the style of padding for multiline comments | ||
#[derive(Clone, Debug, Hash, PartialEq)] | ||
pub enum CommentPaddingStyle { | ||
/// " * ", with container for number of spaces | ||
AsteriskSpace { | ||
/// Number of leading spaces | ||
leading_spaces: usize, | ||
}, | ||
/// Absence of padding | ||
NoPadding, | ||
} | ||
|
||
impl Default for CommentPaddingStyle { | ||
fn default() -> Self { | ||
Self::NoPadding | ||
} | ||
} | ||
|
||
/// A literal with meta info where the first and list whitespace may be found. | ||
#[derive(Clone)] | ||
pub struct TrimmedLiteral { | ||
/// Track what kind of comment the literal is | ||
variant: CommentVariant, | ||
/// The span of rendered content, minus pre and post already applied. | ||
span: Span, | ||
/// The style of the padding for comments, if present | ||
padding_style: CommentPaddingStyle, | ||
/// the complete rendered string including post and pre. | ||
rendered: String, | ||
/// Literal prefix length. | ||
pre: usize, | ||
/// Literal postfix length. | ||
post: usize, | ||
/// Length of rendered **minus** `pre` and `post` in UTF-8 characters. | ||
/// Length of rendered **minus** `pre`, `post`, and `padding` in UTF-8 characters. | ||
len_in_chars: usize, | ||
len_in_bytes: usize, | ||
} | ||
|
@@ -146,6 +166,9 @@ impl std::cmp::PartialEq for TrimmedLiteral { | |
if self.span != other.span { | ||
return false; | ||
} | ||
if self.padding_style != other.padding_style { | ||
return false; | ||
} | ||
if self.variant != other.variant { | ||
return false; | ||
} | ||
|
@@ -161,6 +184,7 @@ impl std::hash::Hash for TrimmedLiteral { | |
self.variant.hash(hasher); | ||
self.rendered.hash(hasher); | ||
self.span.hash(hasher); | ||
self.padding_style.hash(hasher); | ||
self.pre.hash(hasher); | ||
self.post.hash(hasher); | ||
self.len_in_bytes.hash(hasher); | ||
|
@@ -313,6 +337,24 @@ fn detect_comment_variant( | |
Ok((variant, span, pre, post)) | ||
} | ||
|
||
fn detect_and_remove_padding(content: &str) -> (CommentPaddingStyle, usize) { | ||
lazy_static! { | ||
static ref PADDING_STR: Regex = | ||
Regex::new(r##"(?m)^\s\*\s"##).expect("PADDING_STR regex compiles"); | ||
}; | ||
|
||
if let Ok(Some(_)) = PADDING_STR.find(content) { | ||
let padding = CommentPaddingStyle::AsteriskSpace { leading_spaces: 1 }; | ||
let clean_content = PADDING_STR.replace_all(content, ""); | ||
return ( | ||
padding, | ||
content.chars().count() - clean_content.chars().count(), | ||
); | ||
} | ||
|
||
(CommentPaddingStyle::NoPadding, content.len()) | ||
} | ||
|
||
impl TryFrom<(&str, proc_macro2::Literal)> for TrimmedLiteral { | ||
type Error = Error; | ||
fn try_from((content, literal): (&str, proc_macro2::Literal)) -> Result<Self> { | ||
|
@@ -354,6 +396,14 @@ impl TryFrom<(&str, proc_macro2::Literal)> for TrimmedLiteral { | |
log::trace!("extracted from source: >{}< @ {:?}", rendered, span); | ||
let (variant, span, pre, post) = detect_comment_variant(content, &rendered, span)?; | ||
|
||
let (padding_style, padding) = match variant { | ||
CommentVariant::SlashStar | ||
| CommentVariant::SlashAsterisk | ||
| CommentVariant::SlashAsteriskEM | ||
| CommentVariant::SlashAsteriskAsterisk => detect_and_remove_padding(content), | ||
_ => (CommentPaddingStyle::NoPadding, 0), | ||
}; | ||
|
||
let len_in_chars = rendered_len.saturating_sub(post + pre); | ||
|
||
if let Some(span_len) = span.one_line_len() { | ||
|
@@ -372,6 +422,7 @@ impl TryFrom<(&str, proc_macro2::Literal)> for TrimmedLiteral { | |
len_in_bytes, | ||
rendered, | ||
span, | ||
padding_style, | ||
pre, | ||
post, | ||
}; | ||
|
@@ -408,6 +459,7 @@ impl TrimmedLiteral { | |
Ok(TrimmedLiteral { | ||
variant, | ||
span, | ||
padding_style: CommentPaddingStyle::NoPadding, | ||
rendered: content.to_string(), | ||
pre, | ||
post, | ||
|
@@ -471,6 +523,11 @@ impl TrimmedLiteral { | |
self.span.clone() | ||
} | ||
|
||
/// The padding style for this literal. | ||
pub fn padding_style(&self) -> CommentPaddingStyle { | ||
self.padding_style.clone() | ||
} | ||
|
||
/// Access the characters via an iterator. | ||
pub fn chars<'a>(&'a self) -> impl Iterator<Item = char> + 'a { | ||
self.as_str().chars() | ||
|
@@ -626,6 +683,23 @@ mod tests { | |
}); | ||
} | ||
|
||
#[test] | ||
fn padding_style_detect() { | ||
let result = "/**\ndoc\ndoc\n */".to_string(); | ||
assert_matches!( | ||
detect_and_remove_padding("/**\n * doc\n * doc\n */"), | ||
( | ||
CommentPaddingStyle::AsteriskSpace { leading_spaces: 1 }, | ||
result | ||
) | ||
); | ||
let content = "/**\n doc\n doc\n */".to_string(); | ||
assert_matches!( | ||
detect_and_remove_padding(&content), | ||
(CommentPaddingStyle::NoPadding, content) | ||
Comment on lines
+697
to
+699
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 nice use of |
||
); | ||
Comment on lines
+696
to
+700
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer smaller test cases, even if this has a compile time cost to it. And I think we need a few more to cover the indented variants, as in multiple leading spaces before the asterisk. |
||
} | ||
|
||
macro_rules! block_comment_test { | ||
($name:ident, $content:literal) => { | ||
#[test] | ||
|
@@ -656,7 +730,7 @@ mod tests { | |
block_comment_test!( | ||
trimmed_multi_doc, | ||
"/** | ||
mood | ||
* mood | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think both variants should work, the |
||
*/" | ||
); | ||
block_comment_test!( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#202 introduced an optimization to avoid the
regex
entirely and use smid instructions as available, probably worth to hand roll this, but that can be done once you're confident of the structure - this is works and is good for the time being 👍