-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
157 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,6 @@ | ||
[package] | ||
name = "promkit" | ||
version = "0.4.0" | ||
authors = ["ynqa <[email protected]>"] | ||
edition = "2021" | ||
description = "A toolkit for building your own interactive command-line tools" | ||
repository = "https://github.com/ynqa/promkit" | ||
license = "MIT" | ||
readme = "README.md" | ||
|
||
[lib] | ||
name = "promkit" | ||
path = "src/lib.rs" | ||
|
||
[dependencies] | ||
crossterm = { version = "0.27.0", features = ["use-dev-tty"] } | ||
indexmap = "2.2.3" | ||
radix_trie = "0.2.1" | ||
serde = { version = "1.0.197" } | ||
serde_json = { version = "1.0.114", features = ["preserve_order"] } | ||
thiserror = "1.0.50" | ||
unicode-width = "0.1.8" | ||
|
||
[dev-dependencies] | ||
strip-ansi-escapes = "0.2.0" | ||
[workspace] | ||
resolver = "2" | ||
members = [ | ||
"promkit", | ||
"promkit-derive", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
[package] | ||
name = "promkit-derive" | ||
version = "0.1.0" | ||
authors = ["ynqa <[email protected]>"] | ||
edition = "2021" | ||
description = "A derive macro for promkit" | ||
repository = "https://github.com/ynqa/promkit" | ||
license = "MIT" | ||
readme = "README.md" | ||
|
||
[lib] | ||
proc-macro = true | ||
|
||
[dependencies] | ||
syn = { version = "2.0.52", features = ["full"] } | ||
quote = "1.0" | ||
proc-macro2 = "1.0" | ||
promkit = { path = "../promkit", version = "0.4.0" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
use promkit::{crossterm::style::Color, style::StyleBuilder, Result}; | ||
use promkit_derive::Promkit; | ||
|
||
#[derive(Default, Debug, Promkit)] | ||
struct MyStruct { | ||
#[ask( | ||
prefix = "What is your name?", | ||
prefix_style = StyleBuilder::new().fgc(Color::DarkCyan).build(), | ||
)] | ||
name: String, | ||
|
||
#[ask(prefix = "How old are you?", ignore_invalid_attr = "nothing")] | ||
age: usize, | ||
} | ||
|
||
fn main() -> Result { | ||
let ret = MyStruct::default().ask_name()?.ask_age()?; | ||
dbg!(ret); | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
extern crate proc_macro; | ||
|
||
use proc_macro::TokenStream; | ||
use quote::quote; | ||
use syn::{punctuated::Punctuated, DeriveInput, Meta, MetaNameValue, Token}; | ||
|
||
#[proc_macro_derive(Promkit, attributes(ask))] | ||
pub fn promkit_derive(input: TokenStream) -> TokenStream { | ||
let ast: DeriveInput = syn::parse(input).unwrap(); | ||
|
||
let name = &ast.ident; | ||
|
||
let fields = match ast.data { | ||
syn::Data::Struct(s) => s.fields, | ||
_ => panic!("Promkit can only be derived for structs"), | ||
}; | ||
|
||
let mut ask_fns = quote! {}; | ||
let mut run_fns = quote! {}; | ||
|
||
for field in fields.iter() { | ||
for attr in field | ||
.attrs | ||
.iter() | ||
.filter(|attr| attr.path().is_ident("ask")) | ||
{ | ||
let field_ident = field.ident.as_ref().unwrap(); | ||
let field_type = &field.ty; | ||
let ask_fn = syn::Ident::new(&format!("ask_{}", field_ident), field_ident.span()); | ||
let run_fn = syn::Ident::new(&format!("run_{}", field_ident), field_ident.span()); | ||
|
||
ask_fns = quote! { | ||
#ask_fns | ||
|
||
pub fn #ask_fn(mut self) -> promkit::Result<Self> { | ||
let value_str = Self::#run_fn()?; | ||
let parsed_value = value_str.parse::<#field_type>() | ||
.map_err(|e| promkit::Error::ParseError(e.to_string()))?; | ||
self.#field_ident = parsed_value; | ||
Ok(self) | ||
} | ||
}; | ||
|
||
let mut prefix = quote! {}; | ||
let mut mask = quote! {}; | ||
let mut prefix_style = quote! {}; | ||
let mut active_char_style = quote! {}; | ||
let mut inactive_char_style = quote! {}; | ||
|
||
match &attr.meta { | ||
Meta::List(list) => { | ||
list.parse_args_with(Punctuated::<MetaNameValue, Token![,]>::parse_terminated) | ||
.expect("`ask` attribute requires list of namevalue") | ||
.into_iter() | ||
.for_each(|entry| { | ||
match entry.path.get_ident().unwrap().to_string().as_str() { | ||
"prefix" => { | ||
let expr = entry.value; | ||
prefix = quote! { .prefix(format!("{} ", #expr)) }; | ||
} | ||
"mask" => { | ||
let expr = entry.value; | ||
mask = quote! { .mask(#expr) }; | ||
} | ||
"prefix_style" => { | ||
let expr = entry.value; | ||
prefix_style = quote! { .prefix_style(#expr) }; | ||
} | ||
"active_char_style" => { | ||
let expr = entry.value; | ||
active_char_style = quote! { .active_char_style(#expr) }; | ||
} | ||
"inactive_char_style" => { | ||
let expr = entry.value; | ||
inactive_char_style = quote! { .inactive_char_style(#expr) }; | ||
} | ||
_ => (), | ||
} | ||
}); | ||
} | ||
_ => { | ||
panic!("`ask` attribute requires list of namevalue") | ||
} | ||
} | ||
|
||
run_fns = quote! { | ||
#run_fns | ||
|
||
fn #run_fn() -> promkit::Result<String> { | ||
promkit::preset::readline::Readline::default() | ||
#prefix | ||
#mask | ||
#prefix_style | ||
#active_char_style | ||
#inactive_char_style | ||
.prompt()? | ||
.run() | ||
} | ||
}; | ||
} | ||
} | ||
|
||
let expanded = quote! { | ||
impl #name { | ||
#ask_fns | ||
|
||
#run_fns | ||
} | ||
}; | ||
|
||
expanded.into() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
[package] | ||
name = "promkit" | ||
version = "0.3.0" | ||
version = "0.4.0" | ||
authors = ["ynqa <[email protected]>"] | ||
edition = "2021" | ||
description = "A toolkit for building your own interactive command-line tools" | ||
|
@@ -15,7 +15,6 @@ path = "src/lib.rs" | |
[dependencies] | ||
crossterm = { version = "0.27.0", features = ["use-dev-tty"] } | ||
indexmap = "2.2.3" | ||
libc = "0.2.153" | ||
radix_trie = "0.2.1" | ||
serde = { version = "1.0.197" } | ||
serde_json = { version = "1.0.114", features = ["preserve_order"] } | ||
|