Skip to content

Commit

Permalink
refactor(derive): Decouple extracting and formatting of doc comments
Browse files Browse the repository at this point in the history
  • Loading branch information
epage committed Nov 7, 2022
1 parent 214f6b8 commit c1a9da9
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 46 deletions.
29 changes: 5 additions & 24 deletions clap_derive/src/item.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
62 changes: 41 additions & 21 deletions clap_derive/src/utils/doc_comments.rs
Expand Up @@ -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)
Expand All @@ -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..];
Expand Down Expand Up @@ -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(" ")
}
4 changes: 3 additions & 1 deletion clap_derive/src/utils/mod.rs
Expand Up @@ -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},
};

0 comments on commit c1a9da9

Please sign in to comment.