Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
126
vendor/clap_derive/src/utils/doc_comments.rs
vendored
Normal file
126
vendor/clap_derive/src/utils/doc_comments.rs
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
//! The preprocessing we apply to doc comments.
|
||||
//!
|
||||
//! #[derive(Parser)] works in terms of "paragraphs". Paragraph is a sequence of
|
||||
//! non-empty adjacent lines, delimited by sequences of blank (whitespace only) lines.
|
||||
|
||||
use std::iter;
|
||||
|
||||
pub fn extract_doc_comment(attrs: &[syn::Attribute]) -> Vec<String> {
|
||||
// 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<_> = attrs
|
||||
.iter()
|
||||
.filter(|attr| attr.path().is_ident("doc"))
|
||||
.filter_map(|attr| {
|
||||
// non #[doc = "..."] attributes are not our concern
|
||||
// we leave them for rustc to handle
|
||||
match &attr.meta {
|
||||
syn::Meta::NameValue(syn::MetaNameValue {
|
||||
value:
|
||||
syn::Expr::Lit(syn::ExprLit {
|
||||
lit: syn::Lit::Str(s),
|
||||
..
|
||||
}),
|
||||
..
|
||||
}) => Some(s.value()),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
.skip_while(|s| is_blank(s))
|
||||
.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();
|
||||
}
|
||||
|
||||
lines
|
||||
}
|
||||
|
||||
pub fn format_doc_comment(
|
||||
lines: &[String],
|
||||
preprocess: bool,
|
||||
force_long: 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 short = paragraphs[0].clone();
|
||||
let long = paragraphs.join("\n\n");
|
||||
(remove_period(short), long)
|
||||
} else {
|
||||
let short = lines[..first_blank].join("\n");
|
||||
let long = lines.join("\n");
|
||||
(short, long)
|
||||
};
|
||||
|
||||
(Some(short), Some(long))
|
||||
} else {
|
||||
let (short, long) = if preprocess {
|
||||
let short = merge_lines(lines);
|
||||
let long = force_long.then(|| short.clone());
|
||||
let short = remove_period(short);
|
||||
(short, long)
|
||||
} else {
|
||||
let short = lines.join("\n");
|
||||
let long = force_long.then(|| short.clone());
|
||||
(short, long)
|
||||
};
|
||||
|
||||
(Some(short), long)
|
||||
}
|
||||
}
|
||||
|
||||
fn split_paragraphs(lines: &[String]) -> Vec<String> {
|
||||
let mut last_line = 0;
|
||||
iter::from_fn(|| {
|
||||
let slice = &lines[last_line..];
|
||||
let start = slice.iter().position(|s| !is_blank(s)).unwrap_or(0);
|
||||
|
||||
let slice = &slice[start..];
|
||||
let len = slice
|
||||
.iter()
|
||||
.position(|s| is_blank(s))
|
||||
.unwrap_or(slice.len());
|
||||
|
||||
last_line += start + len;
|
||||
|
||||
if len != 0 {
|
||||
Some(merge_lines(&slice[..len]))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn remove_period(mut s: String) -> String {
|
||||
if s.ends_with('.') && !s.ends_with("..") {
|
||||
s.pop();
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
fn is_blank(s: &str) -> bool {
|
||||
s.trim().is_empty()
|
||||
}
|
||||
|
||||
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(" ")
|
||||
}
|
22
vendor/clap_derive/src/utils/error.rs
vendored
Normal file
22
vendor/clap_derive/src/utils/error.rs
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
pub trait SpanError {
|
||||
#[allow(non_snake_case)]
|
||||
fn EXPECTED_Span_OR_ToTokens<D: std::fmt::Display>(&self, msg: D) -> syn::Error;
|
||||
}
|
||||
|
||||
pub trait ToTokensError {
|
||||
#[allow(non_snake_case)]
|
||||
fn EXPECTED_Span_OR_ToTokens<D: std::fmt::Display>(&self, msg: D) -> syn::Error;
|
||||
}
|
||||
|
||||
impl<T: quote::ToTokens> ToTokensError for T {
|
||||
fn EXPECTED_Span_OR_ToTokens<D: std::fmt::Display>(&self, msg: D) -> syn::Error {
|
||||
// Curb monomorphization from generating too many identical `new_spanned`.
|
||||
syn::Error::new_spanned(self.to_token_stream(), msg)
|
||||
}
|
||||
}
|
||||
|
||||
impl SpanError for proc_macro2::Span {
|
||||
fn EXPECTED_Span_OR_ToTokens<D: std::fmt::Display>(&self, msg: D) -> syn::Error {
|
||||
syn::Error::new(*self, msg)
|
||||
}
|
||||
}
|
13
vendor/clap_derive/src/utils/mod.rs
vendored
Normal file
13
vendor/clap_derive/src/utils/mod.rs
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
pub mod error;
|
||||
|
||||
mod doc_comments;
|
||||
mod spanned;
|
||||
mod ty;
|
||||
|
||||
pub use doc_comments::extract_doc_comment;
|
||||
pub use doc_comments::format_doc_comment;
|
||||
|
||||
pub use self::{
|
||||
spanned::Sp,
|
||||
ty::{inner_type, is_simple_ty, sub_type, subty_if_name, Ty},
|
||||
};
|
89
vendor/clap_derive/src/utils/spanned.rs
vendored
Normal file
89
vendor/clap_derive/src/utils/spanned.rs
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::ToTokens;
|
||||
use syn::LitStr;
|
||||
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
/// An entity with a span attached.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Sp<T> {
|
||||
val: T,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl<T> Sp<T> {
|
||||
pub fn new(val: T, span: Span) -> Self {
|
||||
Sp { val, span }
|
||||
}
|
||||
|
||||
pub fn get(&self) -> &T {
|
||||
&self.val
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
self.span
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for Sp<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.val
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for Sp<T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
&mut self.val
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Ident> for Sp<String> {
|
||||
fn from(ident: Ident) -> Self {
|
||||
Sp {
|
||||
val: ident.to_string(),
|
||||
span: ident.span(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LitStr> for Sp<String> {
|
||||
fn from(lit: LitStr) -> Self {
|
||||
Sp {
|
||||
val: lit.value(),
|
||||
span: lit.span(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Sp<&'a str>> for Sp<String> {
|
||||
fn from(sp: Sp<&'a str>) -> Self {
|
||||
Sp::new(sp.val.into(), sp.span)
|
||||
}
|
||||
}
|
||||
|
||||
impl<U, T: PartialEq<U>> PartialEq<U> for Sp<T> {
|
||||
fn eq(&self, other: &U) -> bool {
|
||||
self.val == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<str>> AsRef<str> for Sp<T> {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.val.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToTokens> ToTokens for Sp<T> {
|
||||
fn to_tokens(&self, stream: &mut TokenStream) {
|
||||
// this is the simplest way out of correct ones to change span on
|
||||
// arbitrary token tree I could come up with
|
||||
let tt = self.val.to_token_stream().into_iter().map(|mut tt| {
|
||||
tt.set_span(self.span);
|
||||
tt
|
||||
});
|
||||
|
||||
stream.extend(tt);
|
||||
}
|
||||
}
|
165
vendor/clap_derive/src/utils/ty.rs
vendored
Normal file
165
vendor/clap_derive/src/utils/ty.rs
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
//! Special types handling
|
||||
|
||||
use super::spanned::Sp;
|
||||
|
||||
use syn::{
|
||||
spanned::Spanned, GenericArgument, Path, PathArguments, PathArguments::AngleBracketed,
|
||||
PathSegment, Type, TypePath,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Ty {
|
||||
Unit,
|
||||
Vec,
|
||||
VecVec,
|
||||
Option,
|
||||
OptionOption,
|
||||
OptionVec,
|
||||
OptionVecVec,
|
||||
Other,
|
||||
}
|
||||
|
||||
impl Ty {
|
||||
pub fn from_syn_ty(ty: &syn::Type) -> Sp<Self> {
|
||||
use self::Ty::*;
|
||||
let t = |kind| Sp::new(kind, ty.span());
|
||||
|
||||
if is_unit_ty(ty) {
|
||||
t(Unit)
|
||||
} else if let Some(vt) = get_vec_ty(ty, Vec, VecVec) {
|
||||
t(vt)
|
||||
} else if let Some(subty) = subty_if_name(ty, "Option") {
|
||||
if is_generic_ty(subty, "Option") {
|
||||
t(OptionOption)
|
||||
} else if let Some(vt) = get_vec_ty(subty, OptionVec, OptionVecVec) {
|
||||
t(vt)
|
||||
} else {
|
||||
t(Option)
|
||||
}
|
||||
} else {
|
||||
t(Other)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Unit => "()",
|
||||
Self::Vec => "Vec<T>",
|
||||
Self::Option => "Option<T>",
|
||||
Self::OptionOption => "Option<Option<T>>",
|
||||
Self::OptionVec => "Option<Vec<T>>",
|
||||
Self::VecVec => "Vec<Vec<T>>",
|
||||
Self::OptionVecVec => "Option<Vec<Vec<T>>>",
|
||||
Self::Other => "...other...",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inner_type(field_ty: &syn::Type) -> &syn::Type {
|
||||
let ty = Ty::from_syn_ty(field_ty);
|
||||
match *ty {
|
||||
Ty::Vec | Ty::Option => sub_type(field_ty).unwrap_or(field_ty),
|
||||
Ty::OptionOption | Ty::OptionVec | Ty::VecVec => {
|
||||
sub_type(field_ty).and_then(sub_type).unwrap_or(field_ty)
|
||||
}
|
||||
Ty::OptionVecVec => sub_type(field_ty)
|
||||
.and_then(sub_type)
|
||||
.and_then(sub_type)
|
||||
.unwrap_or(field_ty),
|
||||
_ => field_ty,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sub_type(ty: &syn::Type) -> Option<&syn::Type> {
|
||||
subty_if(ty, |_| true)
|
||||
}
|
||||
|
||||
fn only_last_segment(mut ty: &syn::Type) -> Option<&PathSegment> {
|
||||
while let syn::Type::Group(syn::TypeGroup { elem, .. }) = ty {
|
||||
ty = elem;
|
||||
}
|
||||
match ty {
|
||||
Type::Path(TypePath {
|
||||
qself: None,
|
||||
path:
|
||||
Path {
|
||||
leading_colon: None,
|
||||
segments,
|
||||
},
|
||||
}) => only_one(segments.iter()),
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn subty_if<F>(ty: &syn::Type, f: F) -> Option<&syn::Type>
|
||||
where
|
||||
F: FnOnce(&PathSegment) -> bool,
|
||||
{
|
||||
only_last_segment(ty)
|
||||
.filter(|segment| f(segment))
|
||||
.and_then(|segment| {
|
||||
if let AngleBracketed(args) = &segment.arguments {
|
||||
only_one(args.args.iter()).and_then(|genneric| {
|
||||
if let GenericArgument::Type(ty) = genneric {
|
||||
Some(ty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn subty_if_name<'a>(ty: &'a syn::Type, name: &str) -> Option<&'a syn::Type> {
|
||||
subty_if(ty, |seg| seg.ident == name)
|
||||
}
|
||||
|
||||
pub fn is_simple_ty(ty: &syn::Type, name: &str) -> bool {
|
||||
only_last_segment(ty)
|
||||
.map(|segment| {
|
||||
if let PathArguments::None = segment.arguments {
|
||||
segment.ident == name
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn is_generic_ty(ty: &syn::Type, name: &str) -> bool {
|
||||
subty_if_name(ty, name).is_some()
|
||||
}
|
||||
|
||||
fn is_unit_ty(ty: &syn::Type) -> bool {
|
||||
if let syn::Type::Tuple(tuple) = ty {
|
||||
tuple.elems.is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn only_one<I, T>(mut iter: I) -> Option<T>
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
{
|
||||
iter.next().filter(|_| iter.next().is_none())
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable-v5")]
|
||||
fn get_vec_ty(ty: &Type, vec_ty: Ty, vecvec_ty: Ty) -> Option<Ty> {
|
||||
subty_if_name(ty, "Vec").map(|subty| {
|
||||
if is_generic_ty(subty, "Vec") {
|
||||
vecvec_ty
|
||||
} else {
|
||||
vec_ty
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "unstable-v5"))]
|
||||
fn get_vec_ty(ty: &Type, vec_ty: Ty, _vecvec_ty: Ty) -> Option<Ty> {
|
||||
is_generic_ty(ty, "Vec").then_some(vec_ty)
|
||||
}
|
Reference in New Issue
Block a user