mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-22 14:35:36 +01:00
Support the new line when adding another doc comment
This commit is contained in:
parent
d1ac816642
commit
6fbe7154ba
1 changed files with 42 additions and 16 deletions
|
@ -6,7 +6,7 @@ use crate::{
|
|||
Result,
|
||||
};
|
||||
|
||||
use proc_macro2::Span;
|
||||
use proc_macro2::{Span, TokenTree};
|
||||
use quote::quote_spanned;
|
||||
use syn::{parse::Parser, spanned::Spanned, Attribute};
|
||||
|
||||
|
@ -49,24 +49,32 @@ enum CommandAttrKind {
|
|||
impl CommandAttrs {
|
||||
pub fn from_attributes(attributes: &[Attribute]) -> Result<Self> {
|
||||
use CommandAttrKind::*;
|
||||
// Convert the `doc` attribute into `command(description = "...")`
|
||||
let attributes = attributes.iter().map(|attr| {
|
||||
if attr.path.is_ident("doc") {
|
||||
// Extract the token literal from the doc attribute.
|
||||
let description = parse_doc_comment(attr).unwrap_or_default();
|
||||
// Convert the doc attribute into a command description attribute.
|
||||
let sp = attr.span();
|
||||
let attr = Attribute::parse_outer
|
||||
.parse2(quote_spanned!(sp => #[command(description = #description)]))
|
||||
.unwrap();
|
||||
attr.into_iter().next().unwrap()
|
||||
} else {
|
||||
attr.clone()
|
||||
|
||||
let docs = attributes
|
||||
.iter()
|
||||
.filter_map(|attr| parse_doc_comment(attr).map(|doc| (doc, attr.span())));
|
||||
|
||||
let mut attributes = attributes.to_vec();
|
||||
if docs.clone().count() != 0 {
|
||||
if let Some(des_sp) = get_descripation_span(&attributes) {
|
||||
return Err(compile_error_at(
|
||||
"You cannot use doc comments and #[command(description = \"...\")] \
|
||||
simultaneously\nYou can use only one of them",
|
||||
des_sp,
|
||||
));
|
||||
}
|
||||
});
|
||||
let description = docs.clone().map(|(doc, _)| doc).collect::<Vec<_>>().join("\n");
|
||||
let sp = docs
|
||||
.map(|(_, sp)| sp)
|
||||
.reduce(|acc, sp| acc.join(sp).expect("The spans are in the same file"))
|
||||
.expect("There is at least one doc comment");
|
||||
let attr = Attribute::parse_outer
|
||||
.parse2(quote_spanned! { sp => #[command(description = #description)] })?;
|
||||
attributes.push(attr.into_iter().next().unwrap());
|
||||
}
|
||||
|
||||
fold_attrs(
|
||||
attributes,
|
||||
attributes.into_iter(),
|
||||
is_command_attribute,
|
||||
CommandAttr::parse,
|
||||
Self {
|
||||
|
@ -141,6 +149,24 @@ fn is_command_attribute(a: &Attribute) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the span of the first attribute with a description meta item.
|
||||
fn get_descripation_span(attrs: &[Attribute]) -> Option<Span> {
|
||||
for attr in attrs {
|
||||
for token in attr.tokens.clone() {
|
||||
if let TokenTree::Group(group) = token {
|
||||
for token in group.stream() {
|
||||
if let TokenTree::Ident(ident) = token {
|
||||
if ident == "description" {
|
||||
return Some(group.span());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn parse_doc_comment(attr: &Attribute) -> Option<String> {
|
||||
#[allow(clippy::collapsible_match)]
|
||||
if let syn::Meta::NameValue(syn::MetaNameValue { lit, .. }) = attr.parse_meta().ok()? {
|
||||
|
|
Loading…
Reference in a new issue