mirror of
https://github.com/Drop-OSS/interactive-clap.git
synced 2026-01-30 20:55:25 +01:00
added methods (input_arg())
This commit is contained in:
@@ -17,16 +17,16 @@ pub fn is_field_without_skip_default_from_cli(field: &syn::Field) -> bool {
|
||||
.filter(|attr_token| match attr_token {
|
||||
proc_macro2::TokenTree::Group(group) => {
|
||||
if group.stream().to_string().contains("skip_default_from_cli") {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => abort_call_site!("Only option `TokenTree::Group` is needed"),
|
||||
})
|
||||
},
|
||||
_ => false // abort_call_site!("Only option `TokenTree::Group` is needed")
|
||||
})
|
||||
.next()
|
||||
{
|
||||
Some(token_stream) => true,
|
||||
None => false,
|
||||
Some(token_stream) => false,
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro_error::abort_call_site;
|
||||
use quote::quote;
|
||||
use syn;
|
||||
|
||||
pub fn is_field_without_skip_default_input_arg(field: &syn::Field) -> bool {
|
||||
if field.attrs.is_empty() {
|
||||
return true;
|
||||
}
|
||||
match field
|
||||
.attrs
|
||||
.iter()
|
||||
.filter(|attr| attr.path.is_ident("interactive_clap".into()))
|
||||
.map(|attr| attr.tokens.clone())
|
||||
.flatten()
|
||||
.filter(|attr_token| match attr_token {
|
||||
proc_macro2::TokenTree::Group(group) => {
|
||||
if group
|
||||
.stream()
|
||||
.to_string()
|
||||
.contains("skip_default_input_arg")
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false, // abort_call_site!("Only option `TokenTree::Group` is needed")
|
||||
})
|
||||
.next()
|
||||
{
|
||||
Some(token_stream) => false,
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
@@ -9,23 +9,24 @@ pub fn is_field_without_subcommand(field: &syn::Field) -> bool {
|
||||
return true
|
||||
}
|
||||
match field.attrs.iter()
|
||||
.filter(|attr| attr.path.is_ident("interactive_clap".into()))
|
||||
.map(|attr| attr.tokens.clone())
|
||||
.map(|attr| {
|
||||
attr.tokens.clone()
|
||||
})
|
||||
.flatten()
|
||||
.filter(|attr_token| {
|
||||
match attr_token {
|
||||
proc_macro2::TokenTree::Group(group) => {
|
||||
if group.stream().to_string().contains("named_arg") || group.stream().to_string().contains("subcommand") {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
_ => abort_call_site!("Only option `TokenTree::Group` is needed")
|
||||
_ => false // abort_call_site!("Only option `TokenTree::Group` is needed")
|
||||
}
|
||||
})
|
||||
.next() {
|
||||
Some(token_stream) => true,
|
||||
None => false
|
||||
Some(token_stream) => false,
|
||||
None => true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ pub fn from_cli_for_struct(ast: &syn::DeriveInput, fields: &syn::Fields) -> proc
|
||||
fn fields_value(field: &syn::Field) -> proc_macro2::TokenStream {
|
||||
let ident_field = &field.clone().ident.expect("this field does not exist");
|
||||
let fn_from_cli_arg = syn::Ident::new(&format!("from_cli_{}", &ident_field), Span::call_site());
|
||||
if field.attrs.is_empty() {
|
||||
if super::fields_without_subcommand::is_field_without_subcommand(field) {
|
||||
quote! {
|
||||
let #ident_field = Self::#fn_from_cli_arg(
|
||||
optional_clap_variant
|
||||
@@ -90,38 +90,9 @@ fn fields_value(field: &syn::Field) -> proc_macro2::TokenStream {
|
||||
.and_then(|clap_variant| clap_variant.#ident_field),
|
||||
&context,
|
||||
)?;
|
||||
}
|
||||
} else {
|
||||
match field.attrs.iter()
|
||||
.filter(|attr| attr.path.is_ident("interactive_clap".into()))
|
||||
.map(|attr| attr.tokens.clone())
|
||||
.flatten()
|
||||
.filter(|attr_token| {
|
||||
match attr_token {
|
||||
proc_macro2::TokenTree::Group(group) => {
|
||||
if group.stream().to_string().contains("named_arg") || group.stream().to_string().contains("subcommand") {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
},
|
||||
_ => abort_call_site!("Only option `TokenTree::Group` is needed")
|
||||
}
|
||||
})
|
||||
.map(|_| {
|
||||
quote! {
|
||||
let #ident_field = Self::#fn_from_cli_arg(
|
||||
optional_clap_variant
|
||||
.clone()
|
||||
.and_then(|clap_variant| clap_variant.#ident_field),
|
||||
&context,
|
||||
)?;
|
||||
}
|
||||
})
|
||||
.next() {
|
||||
Some(token_stream) => token_stream,
|
||||
None => quote! ()
|
||||
}
|
||||
} else {
|
||||
quote! ()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro2::Span;
|
||||
use proc_macro_error::abort_call_site;
|
||||
use quote::{__private::ext::RepToTokensExt, quote};
|
||||
use syn;
|
||||
|
||||
pub fn vec_input_arg(
|
||||
ast: &syn::DeriveInput,
|
||||
fields: &syn::Fields,
|
||||
) -> Vec<proc_macro2::TokenStream> {
|
||||
let interactive_clap_attrs_context =
|
||||
super::interactive_clap_attrs_context::InteractiveClapAttrsContext::new(&ast);
|
||||
if interactive_clap_attrs_context.is_skip_default_from_cli {
|
||||
return vec![quote!()];
|
||||
};
|
||||
let vec_fn_input_arg = fields
|
||||
.iter()
|
||||
.filter(|field| super::fields_without_subcommand::is_field_without_subcommand(field))
|
||||
.filter(|field| {
|
||||
super::fields_without_skip_default_input_arg::is_field_without_skip_default_input_arg(
|
||||
field,
|
||||
)
|
||||
})
|
||||
.map(|field| {
|
||||
if field.attrs.is_empty() {
|
||||
return quote!();
|
||||
}
|
||||
let ident_field = &field.clone().ident.expect("this field does not exist");
|
||||
let ty = &field.ty;
|
||||
|
||||
let input_context_dir = interactive_clap_attrs_context
|
||||
.clone()
|
||||
.get_input_context_dir();
|
||||
|
||||
let fn_input_arg =
|
||||
syn::Ident::new(&format!("input_{}", &ident_field), Span::call_site());
|
||||
|
||||
let doc_attrs = field
|
||||
.attrs
|
||||
.iter()
|
||||
.filter(|attr| attr.path.is_ident("doc".into()))
|
||||
.map(|attr| {
|
||||
let mut literal_string = String::new();
|
||||
for attr_token in attr.tokens.clone() {
|
||||
match attr_token {
|
||||
proc_macro2::TokenTree::Literal(literal) => {
|
||||
literal_string = literal.to_string();
|
||||
}
|
||||
_ => (), //abort_call_site!("Only option `TokenTree::Literal` is needed")
|
||||
}
|
||||
}
|
||||
literal_string
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let literal_vec = doc_attrs
|
||||
.iter()
|
||||
.map(|s| s.replace("\"", ""))
|
||||
.collect::<Vec<_>>();
|
||||
let literal = proc_macro2::Literal::string(literal_vec.join("\n ").as_str());
|
||||
|
||||
quote! {
|
||||
fn #fn_input_arg(
|
||||
_context: &#input_context_dir,
|
||||
) -> color_eyre::eyre::Result<#ty> {
|
||||
use dialoguer::Input;
|
||||
Ok(Input::new()
|
||||
.with_prompt(#literal.to_string().as_str())
|
||||
.interact_text()?)
|
||||
}
|
||||
}
|
||||
})
|
||||
.filter(|token_stream| !token_stream.is_empty())
|
||||
.collect::<Vec<proc_macro2::TokenStream>>();
|
||||
vec_fn_input_arg
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
pub mod choose_variant;
|
||||
pub mod cli_field_type;
|
||||
pub mod fields_without_skip_default_from_cli;
|
||||
pub mod fields_without_skip_default_input_arg;
|
||||
pub mod fields_without_subcommand;
|
||||
pub mod from_cli_for_enum;
|
||||
pub mod from_cli_for_struct;
|
||||
pub mod get_arg_from_cli_for_struct;
|
||||
pub mod input_arg;
|
||||
pub mod interactive_clap_attrs_context;
|
||||
|
||||
@@ -97,6 +97,8 @@ pub fn impl_interactive_clap(ast: &syn::DeriveInput) -> TokenStream {
|
||||
|
||||
let fn_get_arg = self::methods::get_arg_from_cli_for_struct::from_cli_arg(&ast, &fields);
|
||||
|
||||
let vec_fn_input_arg = self::methods::input_arg::vec_input_arg(&ast, &fields);
|
||||
|
||||
let context_scope_fields = fields.iter().map(|field| {
|
||||
context_scope_for_struct_field(field)
|
||||
})
|
||||
@@ -183,6 +185,7 @@ pub fn impl_interactive_clap(ast: &syn::DeriveInput) -> TokenStream {
|
||||
impl #name {
|
||||
#(#fn_get_arg)*
|
||||
#fn_from_cli_for_struct
|
||||
#(#vec_fn_input_arg)*
|
||||
|
||||
fn try_parse() -> Result<#cli_name, clap::Error> {
|
||||
<#cli_name as clap::Clap>::try_parse()
|
||||
@@ -334,37 +337,14 @@ fn context_scope_for_struct(name: &syn::Ident, context_scope_fields: Vec<proc_ma
|
||||
fn context_scope_for_struct_field(field: &syn::Field) -> proc_macro2::TokenStream {
|
||||
let ident_field = &field.ident.clone().expect("this field does not exist");
|
||||
let ty = &field.ty;
|
||||
if field.attrs.is_empty() {
|
||||
if self::methods::fields_without_subcommand::is_field_without_subcommand(field) {
|
||||
quote! {
|
||||
pub #ident_field: #ty
|
||||
}
|
||||
} else {
|
||||
match field.attrs.iter()
|
||||
.filter(|attr| attr.path.is_ident("interactive_clap".into()))
|
||||
.map(|attr| attr.tokens.clone())
|
||||
.flatten()
|
||||
.filter(|attr_token| {
|
||||
match attr_token {
|
||||
proc_macro2::TokenTree::Group(group) => {
|
||||
if group.stream().to_string().contains("subcommand") | group.stream().to_string().contains("named_arg") | (group.stream().to_string() == "skip".to_string()) {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
},
|
||||
_ => abort_call_site!("Only option `TokenTree::Group` is needed")
|
||||
}
|
||||
})
|
||||
.map(|_| {
|
||||
quote! {
|
||||
pub #ident_field: #ty
|
||||
}
|
||||
})
|
||||
.next() {
|
||||
Some(token_stream) => token_stream,
|
||||
None => quote! ()
|
||||
}
|
||||
quote! ()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn context_scope_for_enum(name: &syn::Ident) -> proc_macro2::TokenStream {
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
use dialoguer::{theme::ColorfulTheme, Select};
|
||||
use strum::{EnumMessage, IntoEnumIterator};
|
||||
pub fn prompt_variant<T>(prompt: &str) -> T
|
||||
where
|
||||
T: IntoEnumIterator + EnumMessage,
|
||||
T: Copy + Clone,
|
||||
{
|
||||
let variants = T::iter().collect::<Vec<_>>();
|
||||
let actions = variants
|
||||
.iter()
|
||||
.map(|p| {
|
||||
p.get_message()
|
||||
.unwrap_or_else(|| "error[This entry does not have an option message!!]")
|
||||
.to_owned()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let selected = Select::with_theme(&ColorfulTheme::default())
|
||||
.with_prompt(prompt)
|
||||
.items(&actions)
|
||||
.default(0)
|
||||
.interact()
|
||||
.unwrap();
|
||||
|
||||
variants[selected]
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ConnectionConfig {
|
||||
Testnet,
|
||||
Mainnet,
|
||||
Betanet,
|
||||
}
|
||||
Reference in New Issue
Block a user