mirror of
https://github.com/Drop-OSS/interactive-clap.git
synced 2026-07-19 11:53:35 -04:00
feat: Introduced FromCli and ToCliArgs traits to unblock future generics implementation
This commit is contained in:
@@ -7,8 +7,7 @@
|
||||
// ./simple_enum offline => mode: Ok(Offline)
|
||||
// To learn more about the parameters, use "help" flag: ./simple_enum --help
|
||||
|
||||
use dialoguer::{theme::ColorfulTheme, Select};
|
||||
use strum::{EnumDiscriminants, EnumIter, EnumMessage, IntoEnumIterator};
|
||||
use strum::{EnumDiscriminants, EnumIter, EnumMessage};
|
||||
|
||||
#[derive(Debug, Clone, EnumDiscriminants, interactive_clap_derive::InteractiveClap)]
|
||||
#[strum_discriminants(derive(EnumMessage, EnumIter))]
|
||||
@@ -28,6 +27,6 @@ pub enum Mode {
|
||||
fn main() {
|
||||
let cli_mode = Mode::try_parse().ok();
|
||||
let context = (); // default: input_context = ()
|
||||
let mode = Mode::from_cli(cli_mode, context);
|
||||
let mode = <Mode as interactive_clap::FromCli>::from_cli(cli_mode, context);
|
||||
println!("mode: {:?}", mode)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,6 @@ struct Args {
|
||||
fn main() {
|
||||
let cli_args = Args::parse();
|
||||
let context = (); // default: input_context = ()
|
||||
let args = Args::from_cli(Some(cli_args), context);
|
||||
let args = <Args as interactive_clap::FromCli>::from_cli(Some(cli_args), context);
|
||||
println!("args: {:?}", args)
|
||||
}
|
||||
|
||||
@@ -17,14 +17,19 @@ pub struct OfflineArgs {
|
||||
account: Sender,
|
||||
}
|
||||
|
||||
pub struct OfflineArgsContext {}
|
||||
#[derive(Debug)]
|
||||
pub struct OfflineArgsContext {
|
||||
pub some_context_field: i64,
|
||||
}
|
||||
|
||||
impl OfflineArgsContext {
|
||||
fn from_previous_context(
|
||||
_previous_context: (),
|
||||
_scope: &<OfflineArgs as interactive_clap::ToInteractiveClapContextScope>::InteractiveClapContextScope,
|
||||
) -> Self {
|
||||
Self {}
|
||||
Self {
|
||||
some_context_field: 42,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +54,7 @@ pub struct Sender {
|
||||
|
||||
impl Sender {
|
||||
fn input_sender_account_id(context: &OfflineArgsContext) -> color_eyre::eyre::Result<String> {
|
||||
println!("Let's use context: {:?}", context);
|
||||
Ok(dialoguer::Input::new()
|
||||
.with_prompt("What is the account ID?")
|
||||
.interact_text()?)
|
||||
@@ -58,6 +64,6 @@ impl Sender {
|
||||
fn main() {
|
||||
let cli_offline_args = OfflineArgs::parse();
|
||||
let context = (); // #[interactive_clap(input_context = ())]
|
||||
let offline_args = OfflineArgs::from_cli(Some(cli_offline_args), context);
|
||||
let offline_args = <OfflineArgs as interactive_clap::FromCli>::from_cli(Some(cli_offline_args), context);
|
||||
println!("offline_args: {:?}", offline_args)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
// ./struct_with_named_arg account QWERTY => account: Ok(Account { account: Sender { sender_account_id: "QWERTY" } })
|
||||
// To learn more about the parameters, use "help" flag: ./struct_with_named_arg --help
|
||||
|
||||
use clap::Parser;
|
||||
#[derive(Debug, Clone, interactive_clap_derive::InteractiveClap)]
|
||||
struct Account {
|
||||
#[interactive_clap(named_arg)]
|
||||
@@ -24,6 +23,6 @@ pub struct Sender {
|
||||
fn main() {
|
||||
let cli_account = Account::parse();
|
||||
let context = (); // default: input_context = ()
|
||||
let account = Account::from_cli(Some(cli_account), context);
|
||||
let account = <Account as interactive_clap::FromCli>::from_cli(Some(cli_account), context);
|
||||
println!("account: {:?}", account)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,6 @@ pub struct OperationMode {
|
||||
fn main() {
|
||||
let cli_operation_mode = OperationMode::parse();
|
||||
let context = (); // default: input_context = ()
|
||||
let operation_mode = OperationMode::from_cli(Some(cli_operation_mode), context);
|
||||
let operation_mode = <OperationMode as interactive_clap::FromCli>::from_cli(Some(cli_operation_mode), context);
|
||||
println!("operation_mode: {:?}", &operation_mode);
|
||||
}
|
||||
|
||||
+20
-13
@@ -10,6 +10,8 @@
|
||||
use dialoguer::{theme::ColorfulTheme, Select};
|
||||
use strum::{EnumDiscriminants, EnumIter, EnumMessage, IntoEnumIterator};
|
||||
|
||||
use interactive_clap::ToCliArgs;
|
||||
|
||||
mod common;
|
||||
|
||||
#[derive(Debug, Clone, interactive_clap_derive::InteractiveClap)]
|
||||
@@ -30,9 +32,25 @@ pub enum Submit {
|
||||
Display,
|
||||
}
|
||||
|
||||
impl interactive_clap::FromCli for Submit {
|
||||
type FromCliContext = common::ConnectionConfig;
|
||||
type FromCliError = color_eyre::eyre::Error;
|
||||
|
||||
fn from_cli(
|
||||
optional_clap_variant: Option<<Self as interactive_clap::ToCli>::CliVariant>,
|
||||
_context: Self::FromCliContext,
|
||||
) -> Result<Option<Self>, Self::FromCliError> where Self: Sized + interactive_clap::ToCli {
|
||||
let submit: Option<Submit> = optional_clap_variant.clone();
|
||||
match submit {
|
||||
Some(submit) => Ok(Some(submit)),
|
||||
None => Ok(Some(Submit::Display)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Submit {
|
||||
fn choose_variant(
|
||||
connection_config: common::ConnectionConfig,
|
||||
_context: common::ConnectionConfig,
|
||||
) -> color_eyre::eyre::Result<Option<Self>> {
|
||||
let variants = SubmitDiscriminants::iter().collect::<Vec<_>>();
|
||||
let mut submits = variants
|
||||
@@ -52,17 +70,6 @@ impl Submit {
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_cli(
|
||||
optional_clap_variant: Option<<Submit as interactive_clap::ToCli>::CliVariant>,
|
||||
context: common::ConnectionConfig,
|
||||
) -> color_eyre::eyre::Result<Option<Self>> {
|
||||
let submit: Option<Submit> = optional_clap_variant.clone();
|
||||
match submit {
|
||||
Some(submit) => Ok(Some(submit)),
|
||||
None => Ok(Some(Submit::Display)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl interactive_clap::ToCli for Submit {
|
||||
@@ -74,7 +81,7 @@ fn main() {
|
||||
let context = common::ConnectionConfig::Testnet; //#[interactive_clap(context = common::ConnectionConfig)]
|
||||
let online_args = loop {
|
||||
if let Some(args) =
|
||||
OnlineArgs::from_cli(Some(cli_online_args.clone()), context.clone()).unwrap()
|
||||
<OnlineArgs as interactive_clap::FromCli>::from_cli(Some(cli_online_args.clone()), context.clone()).unwrap()
|
||||
{
|
||||
break args;
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ pub fn fn_choose_variant(
|
||||
pub fn choose_variant(context: #input_context) -> color_eyre::eyre::Result<Option<Self>> {
|
||||
loop {
|
||||
#cli_variant
|
||||
if let Some(variant) = Self::from_cli(Some(cli_variant), context.clone())? {
|
||||
if let Some(variant) = <Self as interactive_clap::FromCli>::from_cli(Some(cli_variant), context.clone())? {
|
||||
return Ok(Some(variant));
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,7 +1,6 @@
|
||||
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 {
|
||||
@@ -30,7 +29,7 @@ pub fn is_field_without_skip_default_input_arg(field: &syn::Field) -> bool {
|
||||
})
|
||||
.next()
|
||||
{
|
||||
Some(token_stream) => false,
|
||||
Some(_token_stream) => false,
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,7 +1,6 @@
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro_error::abort_call_site;
|
||||
use quote::quote;
|
||||
use syn;
|
||||
|
||||
pub fn is_field_without_subcommand(field: &syn::Field) -> bool {
|
||||
@@ -29,7 +28,7 @@ pub fn is_field_without_subcommand(field: &syn::Field) -> bool {
|
||||
})
|
||||
.next()
|
||||
{
|
||||
Some(token_stream) => false,
|
||||
Some(_token_stream) => false,
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ pub fn from_cli_for_enum(
|
||||
type Alias = <#name as interactive_clap::ToInteractiveClapContextScope>::InteractiveClapContextScope;
|
||||
let new_context_scope = Alias::#variant_ident;
|
||||
let new_context = #context_name::from_previous_context(context.clone(), &new_context_scope);
|
||||
let optional_inner_args = #ty::from_cli(Some(inner_cli_args), new_context.into())?;
|
||||
let optional_inner_args = <#ty as interactive_clap::FromCli>::from_cli(Some(inner_cli_args), new_context.into())?;
|
||||
if let Some(inner_args) = optional_inner_args {
|
||||
Ok(Some(Self::#variant_ident(inner_args,)))
|
||||
} else {
|
||||
@@ -42,7 +42,7 @@ pub fn from_cli_for_enum(
|
||||
},
|
||||
None => quote! {
|
||||
Some(#cli_name::#variant_ident(inner_cli_args)) => {
|
||||
let optional_inner_args = #ty::from_cli(Some(inner_cli_args), context.clone())?;
|
||||
let optional_inner_args = <#ty as interactive_clap::FromCli>::from_cli(Some(inner_cli_args), context.clone().into())?;
|
||||
if let Some(inner_args) = optional_inner_args {
|
||||
Ok(Some(Self::#variant_ident(inner_args,)))
|
||||
} else {
|
||||
@@ -66,13 +66,17 @@ pub fn from_cli_for_enum(
|
||||
.get_input_context_dir();
|
||||
|
||||
quote! {
|
||||
pub fn from_cli(
|
||||
optional_clap_variant: Option<#cli_name>,
|
||||
context: #input_context_dir,
|
||||
) -> color_eyre::eyre::Result<Option<Self>> {
|
||||
match optional_clap_variant {
|
||||
#(#from_cli_variants)*
|
||||
None => Self::choose_variant(context.clone()),
|
||||
impl interactive_clap::FromCli for #name {
|
||||
type FromCliContext = #input_context_dir;
|
||||
type FromCliError = color_eyre::eyre::Error;
|
||||
fn from_cli(
|
||||
optional_clap_variant: Option<<Self as interactive_clap::ToCli>::CliVariant>,
|
||||
context: Self::FromCliContext,
|
||||
) -> Result<Option<Self>, Self::FromCliError> where Self: Sized + interactive_clap::ToCli {
|
||||
match optional_clap_variant {
|
||||
#(#from_cli_variants)*
|
||||
None => Self::choose_variant(context.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-14
@@ -10,7 +10,6 @@ pub fn from_cli_for_struct(
|
||||
fields: &syn::Fields,
|
||||
) -> proc_macro2::TokenStream {
|
||||
let name = &ast.ident;
|
||||
let cli_name = syn::Ident::new(&format!("Cli{}", name), Span::call_site());
|
||||
|
||||
let interactive_clap_attrs_context =
|
||||
super::interactive_clap_attrs_context::InteractiveClapAttrsContext::new(&ast);
|
||||
@@ -81,15 +80,19 @@ pub fn from_cli_for_struct(
|
||||
};
|
||||
|
||||
quote! {
|
||||
pub fn from_cli(
|
||||
optional_clap_variant: Option<#cli_name>,
|
||||
context: #input_context_dir,
|
||||
) -> color_eyre::eyre::Result<Option<Self>> {
|
||||
#(#fields_value)*
|
||||
#new_context_scope
|
||||
#field_value_named_arg
|
||||
#field_value_subcommand;
|
||||
Ok(Some(Self{ #(#struct_fields,)* }))
|
||||
impl interactive_clap::FromCli for #name {
|
||||
type FromCliContext = #input_context_dir;
|
||||
type FromCliError = color_eyre::eyre::Error;
|
||||
fn from_cli(
|
||||
optional_clap_variant: Option<<Self as interactive_clap::ToCli>::CliVariant>,
|
||||
context: Self::FromCliContext,
|
||||
) -> Result<Option<Self>, Self::FromCliError> where Self: Sized + interactive_clap::ToCli {
|
||||
#(#fields_value)*
|
||||
#new_context_scope
|
||||
#field_value_named_arg
|
||||
#field_value_subcommand;
|
||||
Ok(Some(Self{ #(#struct_fields,)* }))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,7 +158,7 @@ fn field_value_named_arg(
|
||||
let context_for_struct = syn::Ident::new(&format!("{}Context", &name), Span::call_site());
|
||||
quote! {
|
||||
let new_context = #context_for_struct::from_previous_context(context, &new_context_scope);
|
||||
let #ident_field = #ty::from_cli(
|
||||
let #ident_field = <#ty as interactive_clap::FromCli>::from_cli(
|
||||
optional_clap_variant.and_then(|clap_variant| match clap_variant.#ident_field {
|
||||
Some(#enum_for_clap_named_arg::#variant_name(cli_arg)) => Some(cli_arg),
|
||||
None => None,
|
||||
@@ -170,7 +173,7 @@ fn field_value_named_arg(
|
||||
}
|
||||
},
|
||||
None => quote! {
|
||||
let #ident_field = #ty::from_cli(
|
||||
let #ident_field = <#ty as interactive_clap::FromCli>::from_cli(
|
||||
optional_clap_variant.and_then(|clap_variant| match clap_variant.#ident_field {
|
||||
Some(#enum_for_clap_named_arg::#variant_name(cli_sender)) => Some(cli_sender),
|
||||
None => None,
|
||||
@@ -225,7 +228,7 @@ fn field_value_subcommand(
|
||||
quote! {
|
||||
let new_context = #context_for_struct::from_previous_context(context, &new_context_scope);
|
||||
let #ident_field = match optional_clap_variant.and_then(|clap_variant| clap_variant.#ident_field) {
|
||||
Some(cli_arg) => #ty::from_cli(Some(cli_arg), new_context.into())?,
|
||||
Some(cli_arg) => <#ty as interactive_clap::FromCli>::from_cli(Some(cli_arg), new_context.into())?,
|
||||
None => #ty::choose_variant(new_context.into())?,
|
||||
};
|
||||
let #ident_field = if let Some(value) = #ident_field {
|
||||
@@ -237,7 +240,7 @@ fn field_value_subcommand(
|
||||
},
|
||||
None => quote! {
|
||||
let #ident_field = match optional_clap_variant.and_then(|clap_variant| clap_variant.#ident_field) {
|
||||
Some(cli_arg) => #ty::from_cli(Some(cli_arg), context)?,
|
||||
Some(cli_arg) => <#ty as interactive_clap::FromCli>::from_cli(Some(cli_arg), context)?,
|
||||
None => #ty::choose_variant(context.into())?,
|
||||
};
|
||||
let #ident_field = if let Some(value) = #ident_field {
|
||||
|
||||
@@ -2,7 +2,7 @@ extern crate proc_macro;
|
||||
|
||||
use proc_macro2::Span;
|
||||
use proc_macro_error::abort_call_site;
|
||||
use quote::{__private::ext::RepToTokensExt, quote};
|
||||
use quote::quote;
|
||||
use syn;
|
||||
|
||||
pub fn vec_fn_input_arg(
|
||||
|
||||
@@ -197,9 +197,10 @@ pub fn impl_interactive_clap(ast: &syn::DeriveInput) -> TokenStream {
|
||||
|
||||
#context_scope_for_struct
|
||||
|
||||
#fn_from_cli_for_struct
|
||||
|
||||
impl #name {
|
||||
#(#fn_get_arg)*
|
||||
#fn_from_cli_for_struct
|
||||
#(#vec_fn_input_arg)*
|
||||
|
||||
fn try_parse() -> Result<#cli_name, clap::Error> {
|
||||
@@ -333,9 +334,10 @@ pub fn impl_interactive_clap(ast: &syn::DeriveInput) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
#fn_from_cli_for_enum
|
||||
|
||||
impl #name {
|
||||
#fn_choose_variant
|
||||
#fn_from_cli_for_enum
|
||||
|
||||
fn try_parse() -> Result<#cli_name, clap::Error> {
|
||||
<#cli_name as clap::Parser>::try_parse()
|
||||
|
||||
@@ -41,8 +41,8 @@ pub fn impl_to_cli_args(ast: &syn::DeriveInput) -> TokenStream {
|
||||
let args_push_front_vec = args_push_front_vec.into_iter().rev();
|
||||
|
||||
let gen = quote! {
|
||||
impl #cli_name {
|
||||
pub fn to_cli_args(&self) -> std::collections::VecDeque<String> {
|
||||
impl interactive_clap::ToCliArgs for #cli_name {
|
||||
fn to_cli_args(&self) -> std::collections::VecDeque<String> {
|
||||
#args_subcommand;
|
||||
#(#args_push_front_vec; )*
|
||||
args
|
||||
@@ -83,8 +83,8 @@ pub fn impl_to_cli_args(ast: &syn::DeriveInput) -> TokenStream {
|
||||
}
|
||||
});
|
||||
let gen = quote! {
|
||||
impl #cli_name {
|
||||
pub fn to_cli_args(&self) -> std::collections::VecDeque<String> {
|
||||
impl interactive_clap::ToCliArgs for #cli_name {
|
||||
fn to_cli_args(&self) -> std::collections::VecDeque<String> {
|
||||
match self {
|
||||
#( #enum_variants, )*
|
||||
}
|
||||
|
||||
+13
-8
@@ -6,14 +6,6 @@
|
||||
|
||||
pub use interactive_clap_derive::{InteractiveClap, ToCliArgs};
|
||||
|
||||
// pub trait InteractiveClap {
|
||||
// fn interactive_clap();
|
||||
// }
|
||||
|
||||
// pub trait ToCliArgs {
|
||||
// fn to_cli_args();
|
||||
// }
|
||||
|
||||
pub trait ToCli {
|
||||
type CliVariant;
|
||||
}
|
||||
@@ -33,3 +25,16 @@ impl ToCli for u64 {
|
||||
pub trait ToInteractiveClapContextScope {
|
||||
type InteractiveClapContextScope;
|
||||
}
|
||||
|
||||
pub trait ToCliArgs {
|
||||
fn to_cli_args(&self) -> std::collections::VecDeque<String>;
|
||||
}
|
||||
|
||||
pub trait FromCli {
|
||||
type FromCliContext;
|
||||
type FromCliError;
|
||||
fn from_cli(
|
||||
optional_clap_variant: Option<<Self as ToCli>::CliVariant>,
|
||||
context: Self::FromCliContext,
|
||||
) -> Result<Option<Self>, Self::FromCliError> where Self: Sized + ToCli;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user