mirror of
https://github.com/Drop-OSS/interactive-clap.git
synced 2026-07-19 20:03:34 -04:00
refactor: Use a custom ResultFromCli to enable Cancel and Back variants and lift CLI args on Ok/Err (#4)
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
/target
|
||||
.DS_Store
|
||||
Cargo.lock
|
||||
|
||||
Generated
-744
@@ -1,744 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "335867764ed2de42325fafe6d18b8af74ba97ee0c590fa016f157535b42ab04b"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
"clap_lex",
|
||||
"once_cell",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16a1b0f6422af32d5da0c58e2703320f379216ee70198241c84173a8c5ac28f3"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "color-eyre"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f1885697ee8a177096d42f158922251a41973117f6d8a234cee94b9509157b7"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"color-spantrace",
|
||||
"eyre",
|
||||
"indenter",
|
||||
"once_cell",
|
||||
"owo-colors",
|
||||
"tracing-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "color-spantrace"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6eee477a4a8a72f4addd4de416eb56d54bc307b284d6601bafdee1f4ea462d1"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"owo-colors",
|
||||
"tracing-core",
|
||||
"tracing-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crossterm_winapi",
|
||||
"libc",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm_winapi"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f94fa09c2aeea5b8839e414b7b841bf429fd25b9c522116ac97ee87856d88b2"
|
||||
|
||||
[[package]]
|
||||
name = "eyre"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc225d8f637923fe585089fcf03e705c222131232d2c1fb622e84ecf725d0eb8"
|
||||
dependencies = [
|
||||
"indenter",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indenter"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||
|
||||
[[package]]
|
||||
name = "inquire"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6055ce38cac9b10ac819ed4a509d92ccbc60808152c19ff9121c98198964272"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crossterm",
|
||||
"dyn-clone",
|
||||
"lazy_static",
|
||||
"newline-converter",
|
||||
"thiserror",
|
||||
"unicode-segmentation",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "interactive-clap"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"color-eyre",
|
||||
"inquire",
|
||||
"interactive-clap-derive",
|
||||
"shell-words",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "interactive-clap-derive"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.138"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "newline-converter"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f71d09d5c87634207f894c6b31b6a2b2c64ea3bdcf71bd5599fdbbe1600c00f"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa"
|
||||
|
||||
[[package]]
|
||||
name = "owo-colors"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2386b4ebe91c2f7f51082d4cefa145d030e33a1842a96b12e4885cc3c01f7a55"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shell-words"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-mio"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"signal-hook",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
|
||||
dependencies = [
|
||||
"strum_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.24.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d8d93354fe2a8e50d5953f5ae2e47a3fc2ef03292e7ea46e3cc38f549525fb9"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-error"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4d7c0b83d4a500748fa5879461652b361edf5c9d51ede2a2ac03875ca185e24"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.2.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71"
|
||||
dependencies = [
|
||||
"sharded-slab",
|
||||
"thread_local",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
|
||||
+2
-2
@@ -5,7 +5,7 @@ members = [
|
||||
|
||||
[package]
|
||||
name = "interactive-clap"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
authors = ["FroVolod <frol_off@meta.ua>"]
|
||||
edition = "2018"
|
||||
license = "MIT OR Apache-2.0"
|
||||
@@ -15,7 +15,7 @@ description = "Interactive mode extension crate to Command Line Arguments Parser
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
interactive-clap-derive = { path = "interactive-clap-derive", version = "0.1.0" }
|
||||
interactive-clap-derive = { path = "interactive-clap-derive", version = "0.2.0" }
|
||||
strum = { version = "0.24", features = ["derive"] }
|
||||
strum_macros = "0.24"
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
//This example shows how to parse data from the command line to an enum using the "interactive-clap" macro.
|
||||
|
||||
// 1) build an example: cargo build --example advanced_enum
|
||||
// 2) go to the `examples` folder: cd target/debug/examples
|
||||
// 3) run an example: ./advanced_enum (without parameters) => entered interactive mode
|
||||
// ./advanced_enum network => mode: Ok(Network)
|
||||
// ./advanced_enum offline => mode: Ok(Offline)
|
||||
// To learn more about the parameters, use "help" flag: ./advanced_enum --help
|
||||
|
||||
use interactive_clap::{ResultFromCli, ToCliArgs};
|
||||
use strum::{EnumDiscriminants, EnumIter, EnumMessage};
|
||||
|
||||
#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)]
|
||||
#[strum_discriminants(derive(EnumMessage, EnumIter))]
|
||||
///To construct a transaction you will need to provide information about sender (signer) and receiver accounts, and actions that needs to be performed.
|
||||
///Do you want to derive some information required for transaction construction automatically querying it online?
|
||||
pub enum Mode {
|
||||
/// Prepare and, optionally, submit a new transaction with online mode
|
||||
#[strum_discriminants(strum(message = "Yes, I keep it simple"))]
|
||||
Network(Args),
|
||||
/// Prepare and, optionally, submit a new transaction with offline mode
|
||||
#[strum_discriminants(strum(
|
||||
message = "No, I want to work in no-network (air-gapped) environment"
|
||||
))]
|
||||
Offline,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, interactive_clap::InteractiveClap)]
|
||||
pub struct Args {
|
||||
age: u64,
|
||||
first_name: String,
|
||||
second_name: String,
|
||||
}
|
||||
|
||||
fn main() -> color_eyre::Result<()> {
|
||||
let cli_mode = Mode::try_parse().ok();
|
||||
let context = (); // default: input_context = ()
|
||||
let mode = loop {
|
||||
let mode = <Mode as interactive_clap::FromCli>::from_cli(cli_mode.clone(), context);
|
||||
match mode {
|
||||
ResultFromCli::Ok(cli_mode) => break cli_mode,
|
||||
ResultFromCli::Cancel(Some(cli_mode)) => {
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&cli_mode.to_cli_args())
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
ResultFromCli::Cancel(None) => {
|
||||
println!("Goodbye!");
|
||||
return Ok(());
|
||||
}
|
||||
ResultFromCli::Back => {}
|
||||
ResultFromCli::Err(optional_cli_mode, err) => {
|
||||
if let Some(cli_mode) = optional_cli_mode {
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&cli_mode.to_cli_args())
|
||||
);
|
||||
}
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
println!("cli_mode: {:?}", mode);
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&mode.to_cli_args())
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
+90
-56
@@ -7,15 +7,14 @@
|
||||
// => args: Ok(Args { age: 30, first_name: "QWE", second_name: "QWERTY" })
|
||||
// To learn more about the parameters, use "help" flag: ./advanced_struct --help
|
||||
|
||||
use inquire::{CustomType, Text};
|
||||
use interactive_clap::{ResultFromCli, ToCliArgs};
|
||||
|
||||
#[derive(Debug, interactive_clap_derive::InteractiveClap)]
|
||||
#[derive(Debug, Clone, interactive_clap::InteractiveClap)]
|
||||
#[interactive_clap(skip_default_from_cli)]
|
||||
struct Args {
|
||||
#[interactive_clap(long = "age-full-years")] // hgfashdgfajdfsadajsdfh
|
||||
#[interactive_clap(skip_default_from_cli_arg)] // указать для чего этот атрибут нужен
|
||||
#[interactive_clap(long = "age-full-years")]
|
||||
#[interactive_clap(skip_default_input_arg)]
|
||||
age: u64,
|
||||
age: Option<u64>,
|
||||
#[interactive_clap(long)]
|
||||
///What is your first name?
|
||||
first_name: String,
|
||||
@@ -24,62 +23,97 @@ struct Args {
|
||||
second_name: String,
|
||||
}
|
||||
|
||||
impl interactive_clap::FromCli for Args {
|
||||
type FromCliContext = ();
|
||||
type FromCliError = color_eyre::eyre::Error;
|
||||
fn from_cli(
|
||||
optional_clap_variant: Option<<Self as interactive_clap::ToCli>::CliVariant>,
|
||||
context: Self::FromCliContext,
|
||||
) -> ResultFromCli<<Self as interactive_clap::ToCli>::CliVariant, Self::FromCliError>
|
||||
where
|
||||
Self: Sized + interactive_clap::ToCli,
|
||||
{
|
||||
let mut clap_variant = optional_clap_variant.unwrap_or_default();
|
||||
if clap_variant.age.is_none() {
|
||||
clap_variant.age = match Self::input_age(&context) {
|
||||
Ok(optional_age) => optional_age,
|
||||
Err(err) => return ResultFromCli::Err(Some(clap_variant), err),
|
||||
};
|
||||
}
|
||||
let age = clap_variant.age;
|
||||
if clap_variant.first_name.is_none() {
|
||||
clap_variant.first_name = match Self::input_first_name(&context) {
|
||||
Ok(Some(first_name)) => Some(first_name),
|
||||
Ok(None) => return ResultFromCli::Cancel(Some(clap_variant)),
|
||||
Err(err) => return ResultFromCli::Err(Some(clap_variant), err),
|
||||
};
|
||||
}
|
||||
let first_name = clap_variant.first_name.clone().expect("Unexpected error");
|
||||
if clap_variant.second_name.is_none() {
|
||||
clap_variant.second_name = match Self::input_second_name(&context) {
|
||||
Ok(Some(second_name)) => Some(second_name),
|
||||
Ok(None) => return ResultFromCli::Cancel(Some(clap_variant)),
|
||||
Err(err) => return ResultFromCli::Err(Some(clap_variant), err),
|
||||
};
|
||||
}
|
||||
let second_name = clap_variant.second_name.clone().expect("Unexpected error");
|
||||
ResultFromCli::Ok(clap_variant)
|
||||
}
|
||||
}
|
||||
|
||||
impl Args {
|
||||
pub fn from_cli(
|
||||
optional_clap_variant: Option<CliArgs>,
|
||||
context: (),
|
||||
) -> color_eyre::eyre::Result<Option<Self>> {
|
||||
let age = Self::from_cli_age(
|
||||
optional_clap_variant
|
||||
.clone()
|
||||
.and_then(|clap_variant| clap_variant.age),
|
||||
&context,
|
||||
)?;
|
||||
let first_name = Self::from_cli_first_name(
|
||||
optional_clap_variant
|
||||
.clone()
|
||||
.and_then(|clap_variant| clap_variant.first_name),
|
||||
&context,
|
||||
)?;
|
||||
let second_name = Self::from_cli_second_name(
|
||||
optional_clap_variant
|
||||
.clone()
|
||||
.and_then(|clap_variant| clap_variant.second_name),
|
||||
&context,
|
||||
)?;
|
||||
let new_context_scope = InteractiveClapContextScopeForArgs {
|
||||
age,
|
||||
first_name,
|
||||
second_name,
|
||||
};
|
||||
Ok(Some(Self {
|
||||
age: new_context_scope.age,
|
||||
first_name: new_context_scope.first_name,
|
||||
second_name: new_context_scope.second_name,
|
||||
}))
|
||||
fn input_age(_context: &()) -> color_eyre::eyre::Result<Option<u64>> {
|
||||
match inquire::CustomType::new("Input age full years".to_string().as_str()).prompt() {
|
||||
Ok(value) => Ok(Some(value)),
|
||||
Err(
|
||||
inquire::error::InquireError::OperationCanceled
|
||||
| inquire::error::InquireError::OperationInterrupted,
|
||||
) => Ok(None),
|
||||
Err(err) => Err(err.into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn input_age(_context: &()) -> color_eyre::eyre::Result<u64> {
|
||||
Ok(CustomType::new("How old are you?").prompt()?)
|
||||
}
|
||||
|
||||
fn input_second_name(_context: &()) -> color_eyre::eyre::Result<String> {
|
||||
Ok(Text::new("What is your last name?").prompt()?)
|
||||
}
|
||||
|
||||
fn from_cli_age(
|
||||
optional_cli_age: Option<u64>,
|
||||
context: &(), // default: input_context = ()
|
||||
) -> color_eyre::eyre::Result<u64> {
|
||||
match optional_cli_age {
|
||||
Some(age) => Ok(age),
|
||||
None => Self::input_age(&context),
|
||||
fn input_second_name(_context: &()) -> color_eyre::eyre::Result<Option<String>> {
|
||||
match inquire::Text::new("Input second name".to_string().as_str()).prompt() {
|
||||
Ok(value) => Ok(Some(value)),
|
||||
Err(
|
||||
inquire::error::InquireError::OperationCanceled
|
||||
| inquire::error::InquireError::OperationInterrupted,
|
||||
) => Ok(None),
|
||||
Err(err) => Err(err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cli_args = Args::parse();
|
||||
let args = Args::from_cli(Some(cli_args), ());
|
||||
println!("args: {:?}", args)
|
||||
fn main() -> color_eyre::Result<()> {
|
||||
let mut cli_args = Args::parse();
|
||||
let context = (); // default: input_context = ()
|
||||
loop {
|
||||
let args = <Args as interactive_clap::FromCli>::from_cli(Some(cli_args), context);
|
||||
match args {
|
||||
ResultFromCli::Ok(cli_args) | ResultFromCli::Cancel(Some(cli_args)) => {
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&cli_args.to_cli_args())
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
ResultFromCli::Cancel(None) => {
|
||||
println!("Goodbye!");
|
||||
return Ok(());
|
||||
}
|
||||
ResultFromCli::Back => {
|
||||
cli_args = Default::default();
|
||||
}
|
||||
ResultFromCli::Err(cli_args, err) => {
|
||||
if let Some(cli_args) = cli_args {
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&cli_args.to_cli_args())
|
||||
);
|
||||
}
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+29
-4
@@ -7,9 +7,10 @@
|
||||
// ./simple_enum offline => mode: Ok(Offline)
|
||||
// To learn more about the parameters, use "help" flag: ./simple_enum --help
|
||||
|
||||
use interactive_clap::{ResultFromCli, ToCliArgs};
|
||||
use strum::{EnumDiscriminants, EnumIter, EnumMessage};
|
||||
|
||||
#[derive(Debug, Clone, EnumDiscriminants, interactive_clap_derive::InteractiveClap)]
|
||||
#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)]
|
||||
#[strum_discriminants(derive(EnumMessage, EnumIter))]
|
||||
///To construct a transaction you will need to provide information about sender (signer) and receiver accounts, and actions that needs to be performed.
|
||||
///Do you want to derive some information required for transaction construction automatically querying it online?
|
||||
@@ -24,9 +25,33 @@ pub enum Mode {
|
||||
Offline,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn main() -> color_eyre::Result<()> {
|
||||
let cli_mode = Mode::try_parse().ok();
|
||||
let context = (); // default: input_context = ()
|
||||
let mode = <Mode as interactive_clap::FromCli>::from_cli(cli_mode, context);
|
||||
println!("mode: {:?}", mode)
|
||||
loop {
|
||||
let mode = <Mode as interactive_clap::FromCli>::from_cli(cli_mode.clone(), context);
|
||||
match mode {
|
||||
ResultFromCli::Ok(cli_mode) | ResultFromCli::Cancel(Some(cli_mode)) => {
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&cli_mode.to_cli_args())
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
ResultFromCli::Cancel(None) => {
|
||||
println!("Goodbye!");
|
||||
return Ok(());
|
||||
}
|
||||
ResultFromCli::Back => {}
|
||||
ResultFromCli::Err(optional_cli_mode, err) => {
|
||||
if let Some(cli_mode) = optional_cli_mode {
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&cli_mode.to_cli_args())
|
||||
);
|
||||
}
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,16 +6,44 @@
|
||||
// ./simple_struct 30 QWE QWERTY => args: Ok(Args { age: 30, first_name: "QWE", second_name: "QWERTY" })
|
||||
// To learn more about the parameters, use "help" flag: ./simple_struct --help
|
||||
|
||||
#[derive(Debug, interactive_clap::InteractiveClap)]
|
||||
struct Args {
|
||||
use interactive_clap::{ResultFromCli, ToCliArgs};
|
||||
|
||||
#[derive(Debug, Clone, interactive_clap::InteractiveClap)]
|
||||
pub struct Args {
|
||||
age: u64,
|
||||
first_name: String,
|
||||
second_name: String,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cli_args = Args::parse();
|
||||
fn main() -> color_eyre::Result<()> {
|
||||
let mut cli_args = Args::parse();
|
||||
let context = (); // default: input_context = ()
|
||||
let args = <Args as interactive_clap::FromCli>::from_cli(Some(cli_args), context);
|
||||
println!("args: {:?}", args)
|
||||
loop {
|
||||
let args = <Args as interactive_clap::FromCli>::from_cli(Some(cli_args), context);
|
||||
match args {
|
||||
ResultFromCli::Ok(cli_args) | ResultFromCli::Cancel(Some(cli_args)) => {
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&cli_args.to_cli_args())
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
ResultFromCli::Cancel(None) => {
|
||||
println!("Goodbye!");
|
||||
return Ok(());
|
||||
}
|
||||
ResultFromCli::Back => {
|
||||
cli_args = Default::default();
|
||||
}
|
||||
ResultFromCli::Err(cli_args, err) => {
|
||||
if let Some(cli_args) = cli_args {
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&cli_args.to_cli_args())
|
||||
);
|
||||
}
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,17 +6,18 @@
|
||||
// ./struct_with_context account QWERTY => offline_args: Ok(OfflineArgs { account: Sender { sender_account_id: "QWERTY" } })
|
||||
// To learn more about the parameters, use "help" flag: ./struct_with_context --help
|
||||
|
||||
use inquire::Text;
|
||||
use interactive_clap::{ResultFromCli, ToCliArgs};
|
||||
|
||||
mod common;
|
||||
mod simple_enum;
|
||||
|
||||
#[derive(Debug, Clone, interactive_clap_derive::InteractiveClap)]
|
||||
#[derive(Debug, Clone, interactive_clap::InteractiveClap)]
|
||||
#[interactive_clap(input_context = ())]
|
||||
#[interactive_clap(output_context = NetworkContext)]
|
||||
#[interactive_clap(output_context = OfflineArgsContext)]
|
||||
pub struct OfflineArgs {
|
||||
#[interactive_clap(named_arg)]
|
||||
///Specify a sender
|
||||
account: Sender,
|
||||
sender: Sender,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -27,7 +28,7 @@ pub struct OfflineArgsContext {
|
||||
impl OfflineArgsContext {
|
||||
fn from_previous_context(
|
||||
_previous_context: (),
|
||||
scope: &<OfflineArgs as interactive_clap::ToInteractiveClapContextScope>::InteractiveClapContextScope,
|
||||
_scope: &<OfflineArgs as interactive_clap::ToInteractiveClapContextScope>::InteractiveClapContextScope,
|
||||
) -> color_eyre::eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
some_context_field: 42,
|
||||
@@ -43,29 +44,82 @@ impl From<OfflineArgsContext> for NetworkContext {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<()> for NetworkContext {
|
||||
fn from(_: ()) -> Self {
|
||||
Self {
|
||||
connection_config: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NetworkContext> for () {
|
||||
fn from(_: NetworkContext) -> Self {
|
||||
()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NetworkContext {
|
||||
pub connection_config: Option<common::ConnectionConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, interactive_clap_derive::InteractiveClap)]
|
||||
#[derive(Debug, Clone, interactive_clap::InteractiveClap)]
|
||||
#[interactive_clap(context = NetworkContext)]
|
||||
pub struct Sender {
|
||||
#[interactive_clap(skip_default_input_arg)]
|
||||
pub sender_account_id: String,
|
||||
sender_account_id: String,
|
||||
#[interactive_clap(subcommand)]
|
||||
network: simple_enum::Mode,
|
||||
}
|
||||
|
||||
impl Sender {
|
||||
fn input_sender_account_id(context: &NetworkContext) -> color_eyre::eyre::Result<String> {
|
||||
fn input_sender_account_id(
|
||||
context: &NetworkContext,
|
||||
) -> color_eyre::eyre::Result<Option<String>> {
|
||||
println!("Let's use context: {:?}", context);
|
||||
Ok(Text::new("What is the account ID?").prompt()?)
|
||||
match inquire::CustomType::new("What is the account ID?").prompt() {
|
||||
Ok(value) => Ok(Some(value)),
|
||||
Err(
|
||||
inquire::error::InquireError::OperationCanceled
|
||||
| inquire::error::InquireError::OperationInterrupted,
|
||||
) => Ok(None),
|
||||
Err(err) => Err(err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cli_offline_args = OfflineArgs::parse();
|
||||
fn main() -> color_eyre::Result<()> {
|
||||
let mut cli_offline_args = OfflineArgs::parse();
|
||||
let context = (); // #[interactive_clap(input_context = ())]
|
||||
let offline_args =
|
||||
<OfflineArgs as interactive_clap::FromCli>::from_cli(Some(cli_offline_args), context);
|
||||
println!("offline_args: {:?}", offline_args)
|
||||
loop {
|
||||
let offline_args = <OfflineArgs as interactive_clap::FromCli>::from_cli(
|
||||
Some(cli_offline_args.clone()),
|
||||
context,
|
||||
);
|
||||
match offline_args {
|
||||
ResultFromCli::Ok(cli_offline_args) | ResultFromCli::Cancel(Some(cli_offline_args)) => {
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&cli_offline_args.to_cli_args())
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
ResultFromCli::Cancel(None) => {
|
||||
println!("Goodbye!");
|
||||
return Ok(());
|
||||
}
|
||||
ResultFromCli::Back => {
|
||||
cli_offline_args = Default::default();
|
||||
}
|
||||
ResultFromCli::Err(cli_offline_args, err) => {
|
||||
if let Some(cli_offline_args) = cli_offline_args {
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&cli_offline_args.to_cli_args())
|
||||
);
|
||||
}
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,22 +7,50 @@
|
||||
// ./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
|
||||
|
||||
#[derive(Debug, Clone, interactive_clap_derive::InteractiveClap)]
|
||||
use interactive_clap::{ResultFromCli, ToCliArgs};
|
||||
|
||||
#[derive(Debug, Clone, interactive_clap::InteractiveClap)]
|
||||
struct Account {
|
||||
#[interactive_clap(named_arg)]
|
||||
///Specify a sender
|
||||
account: Sender,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, interactive_clap_derive::InteractiveClap)]
|
||||
#[derive(Debug, Clone, interactive_clap::InteractiveClap)]
|
||||
pub struct Sender {
|
||||
///What is the account ID?
|
||||
///What is the sender account ID?
|
||||
pub sender_account_id: String,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cli_account = Account::parse();
|
||||
fn main() -> color_eyre::Result<()> {
|
||||
let mut cli_account = Account::parse();
|
||||
let context = (); // default: input_context = ()
|
||||
let account = <Account as interactive_clap::FromCli>::from_cli(Some(cli_account), context);
|
||||
println!("account: {:?}", account)
|
||||
loop {
|
||||
let account = <Account as interactive_clap::FromCli>::from_cli(Some(cli_account), context);
|
||||
match account {
|
||||
ResultFromCli::Ok(cli_account) | ResultFromCli::Cancel(Some(cli_account)) => {
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&cli_account.to_cli_args())
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
ResultFromCli::Cancel(None) => {
|
||||
println!("Goodbye!");
|
||||
return Ok(());
|
||||
}
|
||||
ResultFromCli::Back => {
|
||||
cli_account = Default::default();
|
||||
}
|
||||
ResultFromCli::Err(cli_account, err) => {
|
||||
if let Some(cli_account) = cli_account {
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&cli_account.to_cli_args())
|
||||
);
|
||||
}
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,18 +7,49 @@
|
||||
// ./struct_with_subcommand offline => operation_mode: Ok(OperationMode { mode: Offline })
|
||||
// To learn more about the parameters, use "help" flag: ./struct_with_subcommand --help
|
||||
|
||||
use interactive_clap::{ResultFromCli, ToCliArgs};
|
||||
|
||||
mod simple_enum;
|
||||
|
||||
#[derive(Debug, Clone, interactive_clap_derive::InteractiveClap)]
|
||||
#[derive(Debug, Clone, interactive_clap::InteractiveClap)]
|
||||
pub struct OperationMode {
|
||||
#[interactive_clap(subcommand)]
|
||||
pub mode: simple_enum::Mode,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cli_operation_mode = OperationMode::parse();
|
||||
fn main() -> color_eyre::Result<()> {
|
||||
let mut cli_operation_mode = OperationMode::parse();
|
||||
let context = (); // default: input_context = ()
|
||||
let operation_mode =
|
||||
<OperationMode as interactive_clap::FromCli>::from_cli(Some(cli_operation_mode), context);
|
||||
println!("operation_mode: {:?}", &operation_mode);
|
||||
loop {
|
||||
let operation_mode = <OperationMode as interactive_clap::FromCli>::from_cli(
|
||||
Some(cli_operation_mode),
|
||||
context,
|
||||
);
|
||||
match operation_mode {
|
||||
ResultFromCli::Ok(cli_operation_mode)
|
||||
| ResultFromCli::Cancel(Some(cli_operation_mode)) => {
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&cli_operation_mode.to_cli_args())
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
ResultFromCli::Cancel(None) => {
|
||||
println!("Goodbye!");
|
||||
return Ok(());
|
||||
}
|
||||
ResultFromCli::Back => {
|
||||
cli_operation_mode = Default::default();
|
||||
}
|
||||
ResultFromCli::Err(cli_operation_mode, err) => {
|
||||
if let Some(cli_operation_mode) = cli_operation_mode {
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&cli_operation_mode.to_cli_args())
|
||||
);
|
||||
}
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+135
-32
@@ -8,54 +8,105 @@
|
||||
// To learn more about the parameters, use "help" flag: ./to_cli_args --help
|
||||
|
||||
use inquire::Select;
|
||||
use interactive_clap::{ResultFromCli, SelectVariantOrBack, ToCliArgs};
|
||||
use strum::{EnumDiscriminants, EnumIter, EnumMessage, IntoEnumIterator};
|
||||
|
||||
use interactive_clap::{SelectVariantOrBack, ToCliArgs};
|
||||
|
||||
mod common;
|
||||
|
||||
#[derive(Debug, Clone, interactive_clap_derive::InteractiveClap)]
|
||||
#[derive(Debug, Clone, interactive_clap::InteractiveClap)]
|
||||
#[interactive_clap(context = common::ConnectionConfig)]
|
||||
struct OnlineArgs {
|
||||
/// What is the name of the network
|
||||
#[interactive_clap(skip_default_input_arg)]
|
||||
network_name: String,
|
||||
#[interactive_clap(subcommand)]
|
||||
submit: Submit,
|
||||
}
|
||||
|
||||
#[derive(Debug, EnumDiscriminants, Clone, clap::Parser, interactive_clap_derive::ToCliArgs)]
|
||||
impl OnlineArgs {
|
||||
fn input_network_name(
|
||||
_context: &common::ConnectionConfig,
|
||||
) -> color_eyre::eyre::Result<Option<String>> {
|
||||
match inquire::Text::new("Input network name").prompt() {
|
||||
Ok(value) => Ok(Some(value)),
|
||||
Err(
|
||||
inquire::error::InquireError::OperationCanceled
|
||||
| inquire::error::InquireError::OperationInterrupted,
|
||||
) => Ok(None),
|
||||
Err(err) => Err(err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, EnumDiscriminants, Clone, clap::Parser)]
|
||||
#[strum_discriminants(derive(EnumMessage, EnumIter))]
|
||||
pub enum Submit {
|
||||
#[strum_discriminants(strum(message = "I want to send the transaction to the network"))]
|
||||
Send,
|
||||
Send(Args),
|
||||
#[strum_discriminants(strum(
|
||||
message = "I only want to print base64-encoded transaction for JSON RPC input and exit"
|
||||
))]
|
||||
Display,
|
||||
}
|
||||
|
||||
#[derive(Debug, EnumDiscriminants, Clone, clap::Parser)]
|
||||
pub enum CliSubmit {
|
||||
Send(CliArgs),
|
||||
Display,
|
||||
}
|
||||
|
||||
impl From<Submit> for CliSubmit {
|
||||
fn from(command: Submit) -> Self {
|
||||
match command {
|
||||
Submit::Send(args) => Self::Send(args.into()),
|
||||
Submit::Display => Self::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>
|
||||
context: Self::FromCliContext,
|
||||
) -> ResultFromCli<<Self as interactive_clap::ToCli>::CliVariant, 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)),
|
||||
match optional_clap_variant {
|
||||
Some(submit) => ResultFromCli::Ok(submit),
|
||||
None => Self::choose_variant(context),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl interactive_clap::ToCliArgs for CliSubmit {
|
||||
fn to_cli_args(&self) -> std::collections::VecDeque<String> {
|
||||
match self {
|
||||
Self::Send(cli_args) => {
|
||||
let mut args = cli_args.to_cli_args();
|
||||
args.push_front("send".to_owned());
|
||||
args
|
||||
}
|
||||
Self::Display => {
|
||||
let mut args = std::collections::VecDeque::new();
|
||||
args.push_front("display".to_owned());
|
||||
args
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Submit {
|
||||
fn choose_variant(
|
||||
_context: common::ConnectionConfig,
|
||||
) -> color_eyre::eyre::Result<Option<Self>> {
|
||||
let selected_variant = Select::new(
|
||||
context: common::ConnectionConfig,
|
||||
) -> ResultFromCli<
|
||||
<Self as interactive_clap::ToCli>::CliVariant,
|
||||
<Self as interactive_clap::FromCli>::FromCliError,
|
||||
> {
|
||||
match Select::new(
|
||||
"How would you like to proceed",
|
||||
SubmitDiscriminants::iter()
|
||||
.map(SelectVariantOrBack::Variant)
|
||||
@@ -63,17 +114,40 @@ impl Submit {
|
||||
.collect(),
|
||||
)
|
||||
.prompt()
|
||||
.unwrap();
|
||||
match selected_variant {
|
||||
SelectVariantOrBack::Variant(SubmitDiscriminants::Send) => Ok(Some(Submit::Send)),
|
||||
SelectVariantOrBack::Variant(SubmitDiscriminants::Display) => Ok(Some(Submit::Display)),
|
||||
SelectVariantOrBack::Back => Ok(None),
|
||||
{
|
||||
Ok(SelectVariantOrBack::Variant(variant)) => ResultFromCli::Ok(match variant {
|
||||
SubmitDiscriminants::Send => {
|
||||
let cli_args =
|
||||
match <Args as interactive_clap::FromCli>::from_cli(None, context) {
|
||||
ResultFromCli::Ok(cli_args) => cli_args,
|
||||
ResultFromCli::Cancel(optional_cli_args) => {
|
||||
return ResultFromCli::Cancel(Some(CliSubmit::Send(
|
||||
optional_cli_args.unwrap_or_default(),
|
||||
)));
|
||||
}
|
||||
ResultFromCli::Back => return ResultFromCli::Back,
|
||||
ResultFromCli::Err(optional_cli_args, err) => {
|
||||
return ResultFromCli::Err(
|
||||
Some(CliSubmit::Send(optional_cli_args.unwrap_or_default())),
|
||||
err,
|
||||
);
|
||||
}
|
||||
};
|
||||
CliSubmit::Send(cli_args)
|
||||
}
|
||||
SubmitDiscriminants::Display => CliSubmit::Display,
|
||||
}),
|
||||
Ok(SelectVariantOrBack::Back) => ResultFromCli::Back,
|
||||
Err(
|
||||
inquire::error::InquireError::OperationCanceled
|
||||
| inquire::error::InquireError::OperationInterrupted,
|
||||
) => ResultFromCli::Cancel(None),
|
||||
Err(err) => ResultFromCli::Err(None, err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl interactive_clap::ToCli for Submit {
|
||||
type CliVariant = Submit;
|
||||
type CliVariant = CliSubmit;
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SubmitDiscriminants {
|
||||
@@ -85,23 +159,52 @@ impl std::fmt::Display for SubmitDiscriminants {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[derive(Debug, Clone, interactive_clap::InteractiveClap, clap::Args)]
|
||||
#[interactive_clap(context = common::ConnectionConfig)]
|
||||
pub struct Args {
|
||||
age: u64,
|
||||
first_name: String,
|
||||
second_name: String,
|
||||
}
|
||||
|
||||
fn main() -> color_eyre::Result<()> {
|
||||
let mut cli_online_args = OnlineArgs::parse();
|
||||
let context = common::ConnectionConfig::Testnet; //#[interactive_clap(context = common::ConnectionConfig)]
|
||||
let online_args = loop {
|
||||
if let Some(args) = <OnlineArgs as interactive_clap::FromCli>::from_cli(
|
||||
Some(cli_online_args.clone()),
|
||||
let cli_args = loop {
|
||||
match <OnlineArgs as interactive_clap::FromCli>::from_cli(
|
||||
Some(cli_online_args),
|
||||
context.clone(),
|
||||
)
|
||||
.unwrap()
|
||||
{
|
||||
break args;
|
||||
) {
|
||||
ResultFromCli::Ok(cli_args) => break cli_args,
|
||||
ResultFromCli::Cancel(Some(cli_args)) => {
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&cli_args.to_cli_args())
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
ResultFromCli::Cancel(None) => {
|
||||
println!("Goodbye!");
|
||||
return Ok(());
|
||||
}
|
||||
ResultFromCli::Back => {
|
||||
cli_online_args = Default::default();
|
||||
}
|
||||
ResultFromCli::Err(cli_args, err) => {
|
||||
if let Some(cli_args) = cli_args {
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&cli_args.to_cli_args())
|
||||
);
|
||||
}
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
cli_online_args = online_args.into();
|
||||
let completed_cli = cli_online_args.to_cli_args();
|
||||
println!("cli_args: {:?}", cli_args);
|
||||
println!(
|
||||
"Your console command: {}",
|
||||
shell_words::join(&completed_cli)
|
||||
shell_words::join(&cli_args.to_cli_args())
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "interactive-clap-derive"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
authors = ["FroVolod <frol_off@meta.ua>"]
|
||||
edition = "2018"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
@@ -12,13 +12,10 @@ pub fn fn_choose_variant(
|
||||
let name = &ast.ident;
|
||||
let interactive_clap_attrs_context =
|
||||
super::interactive_clap_attrs_context::InteractiveClapAttrsContext::new(ast);
|
||||
let command_discriminants =
|
||||
syn::Ident::new(&format!("{}Discriminants", name), Span::call_site());
|
||||
let cli_command = syn::Ident::new(&format!("Cli{}", name), Span::call_site());
|
||||
let command_discriminants = syn::Ident::new(&format!("{name}Discriminants"), Span::call_site());
|
||||
let cli_command = syn::Ident::new(&format!("Cli{name}"), Span::call_site());
|
||||
|
||||
let variant_ident = &variants[0].ident;
|
||||
let mut cli_variant = quote!();
|
||||
let mut actions_push_back = quote! {.chain([SelectVariantOrBack::Back])};
|
||||
let mut ast_attrs: Vec<&str> = std::vec::Vec::new();
|
||||
|
||||
if !ast.attrs.is_empty() {
|
||||
@@ -26,13 +23,7 @@ pub fn fn_choose_variant(
|
||||
if attr.path.is_ident("interactive_clap") {
|
||||
for attr_token in attr.tokens.clone() {
|
||||
if let proc_macro2::TokenTree::Group(group) = attr_token {
|
||||
if group
|
||||
.stream()
|
||||
.to_string()
|
||||
.contains("disable_strum_discriminants")
|
||||
{
|
||||
ast_attrs.push("disable_strum_discriminants");
|
||||
} else if group.stream().to_string().contains("disable_back") {
|
||||
if group.stream().to_string().contains("disable_back") {
|
||||
ast_attrs.push("disable_back");
|
||||
};
|
||||
}
|
||||
@@ -48,106 +39,91 @@ pub fn fn_choose_variant(
|
||||
}
|
||||
};
|
||||
}
|
||||
if ast_attrs.contains(&"disable_strum_discriminants") {
|
||||
match &variants[0].fields {
|
||||
syn::Fields::Unnamed(_) => {
|
||||
cli_variant = quote! {
|
||||
let cli_variant = #cli_command::#variant_ident(Default::default());
|
||||
};
|
||||
}
|
||||
syn::Fields::Unit => {
|
||||
cli_variant = quote! {
|
||||
let cli_variant = #cli_command::#variant_ident;
|
||||
};
|
||||
}
|
||||
_ => abort_call_site!("Only option `Fields::Unnamed` or `Fields::Unit` is needed"),
|
||||
}
|
||||
} else {
|
||||
if ast_attrs.contains(&"disable_back") {
|
||||
actions_push_back = quote!();
|
||||
}
|
||||
if ast_attrs.contains(&"strum_discriminants") {
|
||||
let doc_attrs = ast
|
||||
.attrs
|
||||
.iter()
|
||||
.filter(|attr| attr.path.is_ident("doc"))
|
||||
.map(|attr| {
|
||||
let mut literal_string = String::new();
|
||||
for attr_token in attr.tokens.clone() {
|
||||
if let proc_macro2::TokenTree::Literal(literal) = attr_token {
|
||||
literal_string = literal.to_string();
|
||||
}
|
||||
if ast_attrs.contains(&"strum_discriminants") {
|
||||
let doc_attrs = ast
|
||||
.attrs
|
||||
.iter()
|
||||
.filter(|attr| attr.path.is_ident("doc"))
|
||||
.map(|attr| {
|
||||
let mut literal_string = String::new();
|
||||
for attr_token in attr.tokens.clone() {
|
||||
if let proc_macro2::TokenTree::Literal(literal) = attr_token {
|
||||
literal_string = literal.to_string();
|
||||
}
|
||||
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());
|
||||
|
||||
let enum_variants = variants.iter().map(|variant| {
|
||||
let variant_ident = &variant.ident;
|
||||
|
||||
match &variant.fields {
|
||||
syn::Fields::Unnamed(_) => {
|
||||
quote! {
|
||||
#command_discriminants::#variant_ident => #cli_command::#variant_ident(Default::default())
|
||||
}
|
||||
},
|
||||
syn::Fields::Unit => {
|
||||
quote! {
|
||||
#command_discriminants::#variant_ident => #cli_command::#variant_ident
|
||||
}
|
||||
},
|
||||
_ => abort_call_site!("Only option `Fields::Unnamed` or `Fields::Unit` is needed")
|
||||
}
|
||||
});
|
||||
cli_variant = quote! {
|
||||
use interactive_clap::SelectVariantOrBack;
|
||||
use inquire::Select;
|
||||
use strum::{EnumMessage, IntoEnumIterator};
|
||||
fn prompt_variant<T>(prompt: &str) -> color_eyre::eyre::Result<Option<T>>
|
||||
where
|
||||
T: IntoEnumIterator + EnumMessage,
|
||||
T: Copy + Clone,
|
||||
{
|
||||
let selected_variant = Select::new(
|
||||
prompt,
|
||||
T::iter()
|
||||
.map(SelectVariantOrBack::Variant)
|
||||
#actions_push_back
|
||||
.collect(),
|
||||
)
|
||||
.prompt()?;
|
||||
match selected_variant {
|
||||
SelectVariantOrBack::Variant(variant) => Ok(Some(variant)),
|
||||
SelectVariantOrBack::Back => Ok(None),
|
||||
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());
|
||||
|
||||
let enum_variants = variants.iter().map(|variant| {
|
||||
let variant_ident = &variant.ident;
|
||||
match &variant.fields {
|
||||
syn::Fields::Unnamed(_) => {
|
||||
quote! {
|
||||
#command_discriminants::#variant_ident => {
|
||||
#cli_command::#variant_ident(Default::default())
|
||||
}
|
||||
}
|
||||
};
|
||||
let variant = if let Some(variant) = prompt_variant(#literal.to_string().as_str())? {
|
||||
variant
|
||||
} else {
|
||||
return Ok(None);
|
||||
};
|
||||
let cli_variant = match variant {
|
||||
#( #enum_variants, )*
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
syn::Fields::Unit => {
|
||||
quote! {
|
||||
#command_discriminants::#variant_ident => #cli_command::#variant_ident
|
||||
}
|
||||
}
|
||||
_ => abort_call_site!(
|
||||
"Only option `Fields::Unnamed` or `Fields::Unit` is needed"
|
||||
),
|
||||
}
|
||||
});
|
||||
let actions_push_back = if ast_attrs.contains(&"disable_back") {
|
||||
quote!()
|
||||
} else {
|
||||
quote! {.chain([SelectVariantOrBack::Back])}
|
||||
};
|
||||
|
||||
cli_variant = quote! {
|
||||
use interactive_clap::SelectVariantOrBack;
|
||||
use inquire::Select;
|
||||
use strum::{EnumMessage, IntoEnumIterator};
|
||||
|
||||
let selected_variant = Select::new(
|
||||
#literal,
|
||||
#command_discriminants::iter()
|
||||
.map(SelectVariantOrBack::Variant)
|
||||
#actions_push_back
|
||||
.collect(),
|
||||
)
|
||||
.prompt();
|
||||
match selected_variant {
|
||||
Ok(SelectVariantOrBack::Variant(variant)) => {
|
||||
let cli_args = match variant {
|
||||
#( #enum_variants, )*
|
||||
};
|
||||
return interactive_clap::ResultFromCli::Ok(cli_args);
|
||||
},
|
||||
Ok(SelectVariantOrBack::Back) => return interactive_clap::ResultFromCli::Back,
|
||||
Err(
|
||||
inquire::error::InquireError::OperationCanceled
|
||||
| inquire::error::InquireError::OperationInterrupted,
|
||||
) => return interactive_clap::ResultFromCli::Cancel(None),
|
||||
Err(err) => return interactive_clap::ResultFromCli::Err(None, err.into()),
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
let input_context = interactive_clap_attrs_context.get_input_context_dir();
|
||||
let context = interactive_clap_attrs_context.get_input_context_dir();
|
||||
|
||||
quote! {
|
||||
pub fn choose_variant(context: #input_context) -> color_eyre::eyre::Result<Option<Self>> {
|
||||
loop {
|
||||
#cli_variant
|
||||
if let Some(variant) = <Self as interactive_clap::FromCli>::from_cli(Some(cli_variant), context.clone())? {
|
||||
return Ok(Some(variant));
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn choose_variant(context: #context) -> interactive_clap::ResultFromCli<
|
||||
<Self as interactive_clap::ToCli>::CliVariant,
|
||||
<Self as interactive_clap::FromCli>::FromCliError,
|
||||
> {
|
||||
#cli_variant
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
extern crate proc_macro;
|
||||
|
||||
use syn;
|
||||
|
||||
pub fn is_field_without_skip_default_from_cli_arg(field: &syn::Field) -> bool {
|
||||
if field.attrs.is_empty() {
|
||||
return true;
|
||||
}
|
||||
!field
|
||||
.attrs
|
||||
.iter()
|
||||
.filter(|attr| attr.path.is_ident("interactive_clap"))
|
||||
.flat_map(|attr| attr.tokens.clone())
|
||||
.any(|attr_token| match attr_token {
|
||||
proc_macro2::TokenTree::Group(group) => group
|
||||
.stream()
|
||||
.to_string()
|
||||
.contains("skip_default_from_cli_arg"),
|
||||
_ => false, // abort_call_site!("Only option `TokenTree::Group` is needed")
|
||||
})
|
||||
}
|
||||
@@ -10,7 +10,7 @@ pub fn from_cli_for_enum(
|
||||
variants: &syn::punctuated::Punctuated<syn::Variant, syn::token::Comma>,
|
||||
) -> proc_macro2::TokenStream {
|
||||
let name = &ast.ident;
|
||||
let cli_name = syn::Ident::new(&format!("Cli{}", name), Span::call_site());
|
||||
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);
|
||||
@@ -20,42 +20,74 @@ pub fn from_cli_for_enum(
|
||||
|
||||
let from_cli_variants = variants.iter().map(|variant| {
|
||||
let variant_ident = &variant.ident;
|
||||
|
||||
let output_context = match &interactive_clap_attrs_context.output_context_dir {
|
||||
Some(output_context_dir) => {
|
||||
quote! {
|
||||
type Alias = <#name as interactive_clap::ToInteractiveClapContextScope>::InteractiveClapContextScope;
|
||||
let new_context_scope = Alias::#variant_ident;
|
||||
let output_context = match #output_context_dir::from_previous_context(context.clone(), &new_context_scope) {
|
||||
Ok(new_context) => new_context,
|
||||
Err(err) => return interactive_clap::ResultFromCli::Err(Some(#cli_name::#variant_ident(inner_cli_args)), err),
|
||||
};
|
||||
}
|
||||
}
|
||||
None => {
|
||||
quote! {
|
||||
let output_context = context.clone();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match &variant.fields {
|
||||
syn::Fields::Unnamed(fields) => {
|
||||
let ty = &fields.unnamed[0].ty;
|
||||
let context_name = syn::Ident::new(&format!("{}Context", &name), Span::call_site());
|
||||
|
||||
|
||||
match &interactive_clap_attrs_context.output_context_dir {
|
||||
Some(output_context_dir) => quote! {
|
||||
Some(#cli_name::#variant_ident(inner_cli_args)) => {
|
||||
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 output_context = #output_context_dir::from(new_context);
|
||||
let optional_inner_args = <#ty as interactive_clap::FromCli>::from_cli(Some(inner_cli_args), output_context)?;
|
||||
if let Some(inner_args) = optional_inner_args {
|
||||
Ok(Some(Self::#variant_ident(inner_args,)))
|
||||
} else {
|
||||
Self::choose_variant(context.clone())
|
||||
quote! {
|
||||
Some(#cli_name::#variant_ident(inner_cli_args)) => {
|
||||
#output_context
|
||||
let cli_inner_args = <#ty as interactive_clap::FromCli>::from_cli(Some(inner_cli_args), output_context.into());
|
||||
match cli_inner_args {
|
||||
interactive_clap::ResultFromCli::Ok(cli_args) => {
|
||||
interactive_clap::ResultFromCli::Ok(#cli_name::#variant_ident(cli_args))
|
||||
}
|
||||
}
|
||||
},
|
||||
None => quote! {
|
||||
Some(#cli_name::#variant_ident(inner_cli_args)) => {
|
||||
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 {
|
||||
Self::choose_variant(context.clone())
|
||||
interactive_clap::ResultFromCli::Back => {
|
||||
optional_clap_variant = None;
|
||||
continue;
|
||||
},
|
||||
interactive_clap::ResultFromCli::Cancel(Some(cli_args)) => {
|
||||
interactive_clap::ResultFromCli::Cancel(Some(#cli_name::#variant_ident(cli_args)))
|
||||
}
|
||||
interactive_clap::ResultFromCli::Cancel(None) => {
|
||||
interactive_clap::ResultFromCli::Cancel(None)
|
||||
}
|
||||
interactive_clap::ResultFromCli::Err(Some(cli_args), err) => {
|
||||
interactive_clap::ResultFromCli::Err(Some(#cli_name::#variant_ident(cli_args)), err)
|
||||
}
|
||||
interactive_clap::ResultFromCli::Err(None, err) => {
|
||||
interactive_clap::ResultFromCli::Err(None, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
syn::Fields::Unit => {
|
||||
quote! {
|
||||
Some(#cli_name::#variant_ident) => Ok(Some(Self::#variant_ident)),
|
||||
match &interactive_clap_attrs_context.output_context_dir {
|
||||
Some(output_context_dir) => quote! {
|
||||
Some(#cli_name::#variant_ident) => {
|
||||
type Alias = <#name as interactive_clap::ToInteractiveClapContextScope>::InteractiveClapContextScope;
|
||||
let new_context_scope = Alias::#variant_ident;
|
||||
let output_context = match #output_context_dir::from_previous_context(context.clone(), &new_context_scope) {
|
||||
Ok(new_context) => new_context,
|
||||
Err(err) => return interactive_clap::ResultFromCli::Err(Some(#cli_name::#variant_ident), err),
|
||||
};
|
||||
interactive_clap::ResultFromCli::Ok(#cli_name::#variant_ident)
|
||||
}
|
||||
},
|
||||
None => quote! {
|
||||
Some(#cli_name::#variant_ident) => {
|
||||
interactive_clap::ResultFromCli::Ok(#cli_name::#variant_ident)
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => abort_call_site!("Only option `Fields::Unnamed` or `Fields::Unit` is needed")
|
||||
@@ -71,12 +103,20 @@ pub fn from_cli_for_enum(
|
||||
type FromCliContext = #input_context_dir;
|
||||
type FromCliError = color_eyre::eyre::Error;
|
||||
fn from_cli(
|
||||
optional_clap_variant: Option<<Self as interactive_clap::ToCli>::CliVariant>,
|
||||
mut 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()),
|
||||
) -> interactive_clap::ResultFromCli<<Self as interactive_clap::ToCli>::CliVariant, Self::FromCliError> where Self: Sized + interactive_clap::ToCli {
|
||||
loop {
|
||||
return match optional_clap_variant {
|
||||
#(#from_cli_variants)*
|
||||
None => match Self::choose_variant(context.clone()) {
|
||||
interactive_clap::ResultFromCli::Ok(cli_args) => {
|
||||
optional_clap_variant = Some(cli_args);
|
||||
continue;
|
||||
},
|
||||
result => return result,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+69
-114
@@ -33,13 +33,7 @@ pub fn from_cli_for_struct(
|
||||
|
||||
let field_value_named_arg = if let Some(token_stream) = fields
|
||||
.iter()
|
||||
.map(|field| {
|
||||
field_value_named_arg(
|
||||
name,
|
||||
field,
|
||||
&interactive_clap_attrs_context.output_context_dir,
|
||||
)
|
||||
})
|
||||
.map(|field| field_value_named_arg(name, field))
|
||||
.find(|token_stream| !token_stream.is_empty())
|
||||
{
|
||||
token_stream
|
||||
@@ -49,13 +43,7 @@ pub fn from_cli_for_struct(
|
||||
|
||||
let field_value_subcommand = if let Some(token_stream) = fields
|
||||
.iter()
|
||||
.map(|field| {
|
||||
field_value_subcommand(
|
||||
name,
|
||||
field,
|
||||
&interactive_clap_attrs_context.output_context_dir,
|
||||
)
|
||||
})
|
||||
.map(field_value_subcommand)
|
||||
.find(|token_stream| !token_stream.is_empty())
|
||||
{
|
||||
token_stream
|
||||
@@ -63,11 +51,9 @@ pub fn from_cli_for_struct(
|
||||
quote!()
|
||||
};
|
||||
|
||||
let struct_fields = fields
|
||||
.iter()
|
||||
.map(|field| struct_field(field, &fields_without_subcommand));
|
||||
|
||||
let input_context_dir = interactive_clap_attrs_context.get_input_context_dir();
|
||||
let input_context_dir = interactive_clap_attrs_context
|
||||
.clone()
|
||||
.get_input_context_dir();
|
||||
|
||||
let interactive_clap_context_scope_for_struct = syn::Ident::new(
|
||||
&format!("InteractiveClapContextScopeFor{}", &name),
|
||||
@@ -77,6 +63,19 @@ pub fn from_cli_for_struct(
|
||||
let new_context_scope = #interactive_clap_context_scope_for_struct { #(#fields_without_subcommand,)* };
|
||||
};
|
||||
|
||||
let output_context = match &interactive_clap_attrs_context.output_context_dir {
|
||||
Some(output_context_dir) => {
|
||||
quote! {
|
||||
let output_context = match #output_context_dir::from_previous_context(context.clone(), &new_context_scope) {
|
||||
Ok(new_context) => new_context,
|
||||
Err(err) => return interactive_clap::ResultFromCli::Err(Some(clap_variant), err),
|
||||
};
|
||||
let context = output_context;
|
||||
}
|
||||
}
|
||||
None => quote!(),
|
||||
};
|
||||
|
||||
quote! {
|
||||
impl interactive_clap::FromCli for #name {
|
||||
type FromCliContext = #input_context_dir;
|
||||
@@ -84,12 +83,14 @@ pub fn from_cli_for_struct(
|
||||
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 {
|
||||
) -> interactive_clap::ResultFromCli<<Self as interactive_clap::ToCli>::CliVariant, Self::FromCliError> where Self: Sized + interactive_clap::ToCli {
|
||||
let mut clap_variant = optional_clap_variant.unwrap_or_default();
|
||||
#(#fields_value)*
|
||||
#new_context_scope
|
||||
#output_context
|
||||
#field_value_named_arg
|
||||
#field_value_subcommand;
|
||||
Ok(Some(Self{ #(#struct_fields,)* }))
|
||||
interactive_clap::ResultFromCli::Ok(clap_variant)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,26 +98,25 @@ pub fn from_cli_for_struct(
|
||||
|
||||
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());
|
||||
let fn_input_arg = syn::Ident::new(&format!("input_{}", &ident_field), Span::call_site());
|
||||
if super::fields_without_subcommand::is_field_without_subcommand(field) {
|
||||
quote! {
|
||||
let #ident_field = Self::#fn_from_cli_arg(
|
||||
optional_clap_variant
|
||||
.clone()
|
||||
.and_then(|clap_variant| clap_variant.#ident_field),
|
||||
&context,
|
||||
)?;
|
||||
if clap_variant.#ident_field.is_none() {
|
||||
clap_variant
|
||||
.#ident_field = match Self::#fn_input_arg(&context) {
|
||||
Ok(Some(#ident_field)) => Some(#ident_field),
|
||||
Ok(None) => return interactive_clap::ResultFromCli::Cancel(Some(clap_variant)),
|
||||
Err(err) => return interactive_clap::ResultFromCli::Err(Some(clap_variant), err),
|
||||
};
|
||||
};
|
||||
let #ident_field = clap_variant.#ident_field.clone().expect("Unexpected error");
|
||||
}
|
||||
} else {
|
||||
quote!()
|
||||
}
|
||||
}
|
||||
|
||||
fn field_value_named_arg(
|
||||
name: &syn::Ident,
|
||||
field: &syn::Field,
|
||||
output_context_dir: &Option<proc_macro2::TokenStream>,
|
||||
) -> proc_macro2::TokenStream {
|
||||
fn field_value_named_arg(name: &syn::Ident, field: &syn::Field) -> proc_macro2::TokenStream {
|
||||
let ident_field = &field.clone().ident.expect("this field does not exist");
|
||||
let ty = &field.ty;
|
||||
if field.attrs.is_empty() {
|
||||
@@ -144,38 +144,26 @@ fn field_value_named_arg(
|
||||
let enum_for_clap_named_arg = syn::Ident::new(&format!("ClapNamedArg{}For{}", &type_string, &name), Span::call_site());
|
||||
let variant_name_string = crate::helpers::snake_case_to_camel_case::snake_case_to_camel_case(ident_field.to_string());
|
||||
let variant_name = &syn::Ident::new(&variant_name_string, Span::call_site());
|
||||
match output_context_dir {
|
||||
Some(output_context_dir) => {
|
||||
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 output_context = #output_context_dir::from(new_context);
|
||||
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,
|
||||
}),
|
||||
output_context,
|
||||
)?;
|
||||
let #ident_field = if let Some(value) = #ident_field {
|
||||
value
|
||||
} else {
|
||||
return Ok(None);
|
||||
}
|
||||
quote! {
|
||||
let optional_field = match clap_variant.#ident_field.take() {
|
||||
Some(#enum_for_clap_named_arg::#variant_name(cli_arg)) => Some(cli_arg),
|
||||
None => None,
|
||||
};
|
||||
match <#ty as interactive_clap::FromCli>::from_cli(
|
||||
optional_field,
|
||||
context.into(),
|
||||
) {
|
||||
interactive_clap::ResultFromCli::Ok(cli_field) => {
|
||||
clap_variant.#ident_field = Some(#enum_for_clap_named_arg::#variant_name(cli_field));
|
||||
}
|
||||
},
|
||||
None => quote! {
|
||||
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,
|
||||
}),
|
||||
context.into(),
|
||||
)?;
|
||||
let #ident_field = if let Some(value) = #ident_field {
|
||||
value
|
||||
} else {
|
||||
return Ok(None);
|
||||
interactive_clap::ResultFromCli::Cancel(optional_cli_field) => {
|
||||
clap_variant.#ident_field = optional_cli_field.map(#enum_for_clap_named_arg::#variant_name);
|
||||
return interactive_clap::ResultFromCli::Cancel(Some(clap_variant));
|
||||
}
|
||||
interactive_clap::ResultFromCli::Back => return interactive_clap::ResultFromCli::Back,
|
||||
interactive_clap::ResultFromCli::Err(optional_cli_field, err) => {
|
||||
clap_variant.#ident_field = optional_cli_field.map(#enum_for_clap_named_arg::#variant_name);
|
||||
return interactive_clap::ResultFromCli::Err(Some(clap_variant), err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,11 +175,7 @@ fn field_value_named_arg(
|
||||
}
|
||||
}
|
||||
|
||||
fn field_value_subcommand(
|
||||
name: &syn::Ident,
|
||||
field: &syn::Field,
|
||||
output_context_dir: &Option<proc_macro2::TokenStream>,
|
||||
) -> proc_macro2::TokenStream {
|
||||
fn field_value_subcommand(field: &syn::Field) -> proc_macro2::TokenStream {
|
||||
let ident_field = &field.clone().ident.expect("this field does not exist");
|
||||
let ty = &field.ty;
|
||||
if field.attrs.is_empty() {
|
||||
@@ -207,32 +191,23 @@ fn field_value_subcommand(
|
||||
}
|
||||
})
|
||||
.map(|_| {
|
||||
match output_context_dir {
|
||||
Some(output_context_dir) => {
|
||||
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 output_context = #output_context_dir::from(new_context);
|
||||
let #ident_field = match optional_clap_variant.and_then(|clap_variant| clap_variant.#ident_field) {
|
||||
Some(cli_arg) => <#ty as interactive_clap::FromCli>::from_cli(Some(cli_arg), output_context)?,
|
||||
None => #ty::choose_variant(output_context)?,
|
||||
};
|
||||
let #ident_field = if let Some(value) = #ident_field {
|
||||
value
|
||||
} else {
|
||||
return Ok(None);
|
||||
}
|
||||
quote! {
|
||||
match <#ty as interactive_clap::FromCli>::from_cli(clap_variant.#ident_field.take(), context.into()) {
|
||||
interactive_clap::ResultFromCli::Ok(cli_field) => {
|
||||
clap_variant.#ident_field = Some(cli_field);
|
||||
}
|
||||
},
|
||||
None => quote! {
|
||||
let #ident_field = match optional_clap_variant.and_then(|clap_variant| clap_variant.#ident_field) {
|
||||
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 {
|
||||
value
|
||||
} else {
|
||||
return Ok(None);
|
||||
interactive_clap::ResultFromCli::Cancel(option_cli_field) => {
|
||||
clap_variant.#ident_field = option_cli_field;
|
||||
return interactive_clap::ResultFromCli::Cancel(Some(clap_variant));
|
||||
}
|
||||
interactive_clap::ResultFromCli::Cancel(option_cli_field) => {
|
||||
clap_variant.#ident_field = option_cli_field;
|
||||
return interactive_clap::ResultFromCli::Cancel(Some(clap_variant));
|
||||
}
|
||||
interactive_clap::ResultFromCli::Back => return interactive_clap::ResultFromCli::Back,
|
||||
interactive_clap::ResultFromCli::Err(option_cli_field, err) => {
|
||||
clap_variant.#ident_field = option_cli_field;
|
||||
return interactive_clap::ResultFromCli::Err(Some(clap_variant), err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,23 +218,3 @@ fn field_value_subcommand(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn struct_field(
|
||||
field: &syn::Field,
|
||||
fields_without_subcommand: &[proc_macro2::TokenStream],
|
||||
) -> proc_macro2::TokenStream {
|
||||
let ident_field = &field.clone().ident.expect("this field does not exist");
|
||||
if fields_without_subcommand
|
||||
.iter()
|
||||
.map(|token_stream| token_stream.to_string())
|
||||
.any(|x| *ident_field == x)
|
||||
{
|
||||
quote! {
|
||||
#ident_field: new_context_scope.#ident_field
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#ident_field
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-104
@@ -1,104 +0,0 @@
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro2::Span;
|
||||
use quote::quote;
|
||||
use syn;
|
||||
|
||||
pub fn from_cli_arg(ast: &syn::DeriveInput, fields: &syn::Fields) -> Vec<proc_macro2::TokenStream> {
|
||||
let interactive_clap_attrs_context =
|
||||
super::interactive_clap_attrs_context::InteractiveClapAttrsContext::new(ast);
|
||||
|
||||
let fields_without_subcommand = fields
|
||||
.iter()
|
||||
.filter(|field| super::fields_without_subcommand::is_field_without_subcommand(field))
|
||||
.map(|field| {
|
||||
let ident_field = &field.clone().ident.expect("this field does not exist");
|
||||
quote! {#ident_field}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let fields_without_skip_default_from_cli_arg = fields
|
||||
.iter()
|
||||
.filter(|field| {
|
||||
super::fields_without_skip_default_from_cli_arg::is_field_without_skip_default_from_cli_arg(
|
||||
field,
|
||||
)
|
||||
})
|
||||
.map(|field| {
|
||||
let ident_field = &field.clone().ident.expect("this field does not exist");
|
||||
quote! {#ident_field}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let get_arg_for_fields = fields
|
||||
.iter()
|
||||
.map(|field| {
|
||||
let ident_field = &field.clone().ident.expect("this field does not exist");
|
||||
let ty = &field.ty;
|
||||
let fields_without_subcommand_to_string = fields_without_subcommand
|
||||
.iter()
|
||||
.map(|token_stream| token_stream.to_string())
|
||||
.collect::<Vec<_>>();
|
||||
let fields_without_skip_default_from_cli_arg_to_string =
|
||||
fields_without_skip_default_from_cli_arg
|
||||
.iter()
|
||||
.map(|token_stream| token_stream.to_string())
|
||||
.collect::<Vec<_>>();
|
||||
if fields_without_subcommand_to_string.contains(&ident_field.to_string())
|
||||
& fields_without_skip_default_from_cli_arg_to_string
|
||||
.iter()
|
||||
.map(|token_stream| token_stream.to_string())
|
||||
.any(|x| *ident_field == x)
|
||||
{
|
||||
let fn_from_cli_arg =
|
||||
syn::Ident::new(&format!("from_cli_{}", &ident_field), Span::call_site());
|
||||
let optional_cli_field_name =
|
||||
syn::Ident::new(&format!("optional_cli_{}", ident_field), Span::call_site());
|
||||
let input_context_dir = interactive_clap_attrs_context
|
||||
.clone()
|
||||
.get_input_context_dir();
|
||||
let cli_field_type = super::cli_field_type::cli_field_type(ty);
|
||||
let fn_input_arg =
|
||||
syn::Ident::new(&format!("input_{}", &ident_field), Span::call_site());
|
||||
|
||||
let type_string = match &ty {
|
||||
syn::Type::Path(type_path) => match type_path.path.segments.last() {
|
||||
Some(path_segment) => path_segment.ident.to_string(),
|
||||
_ => String::new(),
|
||||
},
|
||||
_ => String::new(),
|
||||
};
|
||||
if let "Option" = type_string.as_str() {
|
||||
quote! {
|
||||
fn #fn_from_cli_arg(
|
||||
#optional_cli_field_name: #cli_field_type,
|
||||
context: &#input_context_dir,
|
||||
) -> color_eyre::eyre::Result<#ty> {
|
||||
match #optional_cli_field_name {
|
||||
Some(#ident_field) => Ok(Some(#ident_field)),
|
||||
None => Self::#fn_input_arg(&context),
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
fn #fn_from_cli_arg(
|
||||
#optional_cli_field_name: #cli_field_type,
|
||||
context: &#input_context_dir,
|
||||
) -> color_eyre::eyre::Result<#ty> {
|
||||
match #optional_cli_field_name {
|
||||
Some(#ident_field) => Ok(#ident_field),
|
||||
None => Self::#fn_input_arg(&context),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote!()
|
||||
}
|
||||
})
|
||||
.filter(|token_stream| !token_stream.is_empty())
|
||||
.collect::<Vec<proc_macro2::TokenStream>>();
|
||||
|
||||
get_arg_for_fields
|
||||
}
|
||||
@@ -34,8 +34,12 @@ pub fn vec_fn_input_arg(
|
||||
return quote! {
|
||||
fn #fn_input_arg(
|
||||
_context: &#input_context_dir,
|
||||
) -> color_eyre::eyre::Result<#ty> {
|
||||
Ok(inquire::CustomType::new(#promt).prompt()?)
|
||||
) -> color_eyre::eyre::Result<Option<#ty>> {
|
||||
match inquire::CustomType::new(#promt).prompt() {
|
||||
Ok(value) => Ok(Some(value)),
|
||||
Err(inquire::error::InquireError::OperationCanceled | inquire::error::InquireError::OperationInterrupted) => Ok(None),
|
||||
Err(err) => Err(err.into()),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -63,8 +67,12 @@ pub fn vec_fn_input_arg(
|
||||
quote! {
|
||||
fn #fn_input_arg(
|
||||
_context: &#input_context_dir,
|
||||
) -> color_eyre::eyre::Result<#ty> {
|
||||
Ok(inquire::CustomType::new(#literal.to_string().as_str()).prompt()?)
|
||||
) -> color_eyre::eyre::Result<Option<#ty>> {
|
||||
match inquire::CustomType::new(#literal).prompt() {
|
||||
Ok(value) => Ok(Some(value)),
|
||||
Err(inquire::error::InquireError::OperationCanceled | inquire::error::InquireError::OperationInterrupted) => Ok(None),
|
||||
Err(err) => Err(err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
pub mod choose_variant;
|
||||
pub mod cli_field_type;
|
||||
pub mod fields_without_skip_default_from_cli_arg;
|
||||
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;
|
||||
|
||||
@@ -112,8 +112,6 @@ pub fn impl_interactive_clap(ast: &syn::DeriveInput) -> TokenStream {
|
||||
let fn_from_cli_for_struct =
|
||||
self::methods::from_cli_for_struct::from_cli_for_struct(ast, &fields);
|
||||
|
||||
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_fn_input_arg(ast, &fields);
|
||||
|
||||
let context_scope_fields = fields
|
||||
@@ -175,7 +173,7 @@ pub fn impl_interactive_clap(ast: &syn::DeriveInput) -> TokenStream {
|
||||
};
|
||||
|
||||
let gen = quote! {
|
||||
#[derive(Debug, Default, Clone, clap::Parser, interactive_clap_derive::ToCliArgs)]
|
||||
#[derive(Debug, Default, Clone, clap::Parser, interactive_clap::ToCliArgs)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
pub struct #cli_name {
|
||||
#( #cli_fields, )*
|
||||
@@ -190,7 +188,6 @@ pub fn impl_interactive_clap(ast: &syn::DeriveInput) -> TokenStream {
|
||||
#fn_from_cli_for_struct
|
||||
|
||||
impl #name {
|
||||
#(#fn_get_arg)*
|
||||
#(#vec_fn_input_arg)*
|
||||
|
||||
fn try_parse() -> Result<#cli_name, clap::Error> {
|
||||
@@ -305,7 +302,7 @@ pub fn impl_interactive_clap(ast: &syn::DeriveInput) -> TokenStream {
|
||||
self::methods::from_cli_for_enum::from_cli_for_enum(ast, variants);
|
||||
|
||||
let gen = quote! {
|
||||
#[derive(Debug, Clone, clap::Parser, interactive_clap_derive::ToCliArgs)]
|
||||
#[derive(Debug, Clone, clap::Parser, interactive_clap::ToCliArgs)]
|
||||
pub enum #cli_name {
|
||||
#( #enum_variants, )*
|
||||
}
|
||||
|
||||
+8
-1
@@ -30,13 +30,20 @@ pub trait ToCliArgs {
|
||||
fn to_cli_args(&self) -> std::collections::VecDeque<String>;
|
||||
}
|
||||
|
||||
pub enum ResultFromCli<T, E> {
|
||||
Ok(T),
|
||||
Cancel(Option<T>),
|
||||
Back,
|
||||
Err(Option<T>, E),
|
||||
}
|
||||
|
||||
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>
|
||||
) -> ResultFromCli<<Self as ToCli>::CliVariant, Self::FromCliError>
|
||||
where
|
||||
Self: Sized + ToCli;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user