mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-18 15:20:15 +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,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
use proc_macro2::Span;
|
use proc_macro2::{Span, TokenTree};
|
||||||
use quote::quote_spanned;
|
use quote::quote_spanned;
|
||||||
use syn::{parse::Parser, spanned::Spanned, Attribute};
|
use syn::{parse::Parser, spanned::Spanned, Attribute};
|
||||||
|
|
||||||
|
@ -49,24 +49,32 @@ enum CommandAttrKind {
|
||||||
impl CommandAttrs {
|
impl CommandAttrs {
|
||||||
pub fn from_attributes(attributes: &[Attribute]) -> Result<Self> {
|
pub fn from_attributes(attributes: &[Attribute]) -> Result<Self> {
|
||||||
use CommandAttrKind::*;
|
use CommandAttrKind::*;
|
||||||
// Convert the `doc` attribute into `command(description = "...")`
|
|
||||||
let attributes = attributes.iter().map(|attr| {
|
let docs = attributes
|
||||||
if attr.path.is_ident("doc") {
|
.iter()
|
||||||
// Extract the token literal from the doc attribute.
|
.filter_map(|attr| parse_doc_comment(attr).map(|doc| (doc, attr.span())));
|
||||||
let description = parse_doc_comment(attr).unwrap_or_default();
|
|
||||||
// Convert the doc attribute into a command description attribute.
|
let mut attributes = attributes.to_vec();
|
||||||
let sp = attr.span();
|
if docs.clone().count() != 0 {
|
||||||
let attr = Attribute::parse_outer
|
if let Some(des_sp) = get_descripation_span(&attributes) {
|
||||||
.parse2(quote_spanned!(sp => #[command(description = #description)]))
|
return Err(compile_error_at(
|
||||||
.unwrap();
|
"You cannot use doc comments and #[command(description = \"...\")] \
|
||||||
attr.into_iter().next().unwrap()
|
simultaneously\nYou can use only one of them",
|
||||||
} else {
|
des_sp,
|
||||||
attr.clone()
|
));
|
||||||
|
}
|
||||||
|
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(
|
fold_attrs(
|
||||||
attributes,
|
attributes.into_iter(),
|
||||||
is_command_attribute,
|
is_command_attribute,
|
||||||
CommandAttr::parse,
|
CommandAttr::parse,
|
||||||
Self {
|
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> {
|
fn parse_doc_comment(attr: &Attribute) -> Option<String> {
|
||||||
#[allow(clippy::collapsible_match)]
|
#[allow(clippy::collapsible_match)]
|
||||||
if let syn::Meta::NameValue(syn::MetaNameValue { lit, .. }) = attr.parse_meta().ok()? {
|
if let syn::Meta::NameValue(syn::MetaNameValue { lit, .. }) = attr.parse_meta().ok()? {
|
||||||
|
|
Loading…
Reference in a new issue