refactor(derive): Decouple extracting and formatting of doc comments

This commit is contained in:
Ed Page
2022-11-07 09:17:04 -06:00
parent e49aacf1bc
commit 31ab2d17df
3 changed files with 49 additions and 46 deletions
+5 -24
View File
@@ -19,13 +19,10 @@ use proc_macro2::{self, Span, TokenStream};
use proc_macro_error::abort;
use quote::{format_ident, quote, quote_spanned, ToTokens};
use syn::DeriveInput;
use syn::{
self, ext::IdentExt, spanned::Spanned, Attribute, Field, Ident, LitStr, MetaNameValue, Type,
Variant,
};
use syn::{self, ext::IdentExt, spanned::Spanned, Attribute, Field, Ident, LitStr, Type, Variant};
use crate::attr::*;
use crate::utils::{inner_type, is_simple_ty, process_doc_comment, Sp, Ty};
use crate::utils::{extract_doc_comment, format_doc_comment, inner_type, is_simple_ty, Sp, Ty};
/// Default casing style for generated arguments.
pub const DEFAULT_CASING: CasingStyle = CasingStyle::Kebab;
@@ -873,26 +870,10 @@ impl Item {
}
fn push_doc_comment(&mut self, attrs: &[Attribute], short_name: &str, long_name: Option<&str>) {
use syn::Lit::*;
use syn::Meta::*;
let lines = extract_doc_comment(attrs);
let comment_parts: Vec<_> = attrs
.iter()
.filter(|attr| attr.path.is_ident("doc"))
.filter_map(|attr| {
if let Ok(NameValue(MetaNameValue { lit: Str(s), .. })) = attr.parse_meta() {
Some(s.value())
} else {
// non #[doc = "..."] attributes are not our concern
// we leave them for rustc to handle
None
}
})
.collect();
if let Some((short_help, long_help)) =
process_doc_comment(&comment_parts, !self.verbatim_doc_comment)
{
if !lines.is_empty() {
let (short_help, long_help) = format_doc_comment(&lines, !self.verbatim_doc_comment);
let short_name = format_ident!("{}", short_name);
let short = Method::new(
short_name,
+41 -21
View File
@@ -5,36 +5,52 @@
use std::iter;
pub fn process_doc_comment(
lines: &[String],
preprocess: bool,
) -> Option<(Option<String>, Option<String>)> {
pub fn extract_doc_comment(attrs: &[syn::Attribute]) -> Vec<String> {
use syn::Lit::*;
use syn::Meta::*;
use syn::MetaNameValue;
// multiline comments (`/** ... */`) may have LFs (`\n`) in them,
// we need to split so we could handle the lines correctly
//
// we also need to remove leading and trailing blank lines
let mut lines: Vec<&str> = lines
let mut lines: Vec<_> = attrs
.iter()
.filter(|attr| attr.path.is_ident("doc"))
.filter_map(|attr| {
if let Ok(NameValue(MetaNameValue { lit: Str(s), .. })) = attr.parse_meta() {
Some(s.value())
} else {
// non #[doc = "..."] attributes are not our concern
// we leave them for rustc to handle
None
}
})
.skip_while(|s| is_blank(s))
.flat_map(|s| s.split('\n'))
.flat_map(|s| {
let lines = s
.split('\n')
.map(|s| {
// remove one leading space no matter what
let s = s.strip_prefix(' ').unwrap_or(s);
s.to_owned()
})
.collect::<Vec<_>>();
lines
})
.collect();
while let Some(true) = lines.last().map(|s| is_blank(s)) {
lines.pop();
}
if lines.is_empty() {
return None;
}
// remove one leading space no matter what
for line in lines.iter_mut() {
*line = line.strip_prefix(' ').unwrap_or(line);
}
lines
}
pub fn format_doc_comment(lines: &[String], preprocess: bool) -> (Option<String>, Option<String>) {
if let Some(first_blank) = lines.iter().position(|s| is_blank(s)) {
let (short, long) = if preprocess {
let paragraphs = split_paragraphs(&lines);
let paragraphs = split_paragraphs(lines);
let short = paragraphs[0].clone();
let long = paragraphs.join("\n\n");
(remove_period(short), long)
@@ -44,20 +60,20 @@ pub fn process_doc_comment(
(short, long)
};
Some((Some(short), Some(long)))
(Some(short), Some(long))
} else {
let short = if preprocess {
let s = merge_lines(&lines);
let s = merge_lines(lines);
remove_period(s)
} else {
lines.join("\n")
};
Some((Some(short), None))
(Some(short), None)
}
}
fn split_paragraphs(lines: &[&str]) -> Vec<String> {
fn split_paragraphs(lines: &[String]) -> Vec<String> {
let mut last_line = 0;
iter::from_fn(|| {
let slice = &lines[last_line..];
@@ -91,6 +107,10 @@ fn is_blank(s: &str) -> bool {
s.trim().is_empty()
}
fn merge_lines(lines: &[&str]) -> String {
lines.iter().map(|s| s.trim()).collect::<Vec<_>>().join(" ")
fn merge_lines(lines: impl IntoIterator<Item = impl AsRef<str>>) -> String {
lines
.into_iter()
.map(|s| s.as_ref().trim().to_owned())
.collect::<Vec<_>>()
.join(" ")
}
+3 -1
View File
@@ -2,8 +2,10 @@ mod doc_comments;
mod spanned;
mod ty;
pub use doc_comments::extract_doc_comment;
pub use doc_comments::format_doc_comment;
pub use self::{
doc_comments::process_doc_comment,
spanned::Sp,
ty::{inner_type, is_simple_ty, sub_type, subty_if_name, Ty},
};