diff --git a/Cargo.lock b/Cargo.lock index 68fa4ec..ee4ba25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,17 +6,18 @@ version = 3 name = "CuTE" version = "0.1.0" dependencies = [ - "chrono", - "crossterm 0.27.0", - "curl", - "lazy_static", - "mockito", - "ratatui 0.23.0", - "rusqlite", - "serde", - "serde_json", - "tui-input", - "tui-widget-list", + "chrono", + "crossterm 0.27.0", + "curl", + "lazy_static", + "mockito", + "ratatui 0.23.0", + "regex", + "rusqlite", + "serde", + "serde_json", + "tui-input", + "tui-widget-list", ] [[package]] @@ -25,7 +26,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ - "gimli", + "gimli", ] [[package]] @@ -40,9 +41,9 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ - "cfg-if", - "once_cell", - "version_check", + "cfg-if", + "once_cell", + "version_check", ] [[package]] @@ -51,7 +52,7 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" dependencies = [ - "memchr", + "memchr", ] [[package]] @@ -72,7 +73,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ - "libc", + "libc", ] [[package]] @@ -81,8 +82,8 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" dependencies = [ - "serde", - "serde_json", + "serde", + "serde_json", ] [[package]] @@ -97,13 +98,13 @@ version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", ] [[package]] @@ -142,7 +143,7 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ - "libc", + "libc", ] [[package]] @@ -157,12 +158,12 @@ version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-targets", + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets", ] [[package]] @@ -171,9 +172,9 @@ version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" dependencies = [ - "is-terminal", - "lazy_static", - "windows-sys 0.48.0", + "is-terminal", + "lazy_static", + "windows-sys 0.48.0", ] [[package]] @@ -188,14 +189,14 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13" dependencies = [ - "bitflags 1.3.2", - "crossterm_winapi", - "libc", - "mio", - "parking_lot", - "signal-hook", - "signal-hook-mio", - "winapi", + "bitflags 1.3.2", + "crossterm_winapi", + "libc", + "mio", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", ] [[package]] @@ -204,14 +205,14 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" dependencies = [ - "bitflags 2.4.0", - "crossterm_winapi", - "libc", - "mio", - "parking_lot", - "signal-hook", - "signal-hook-mio", - "winapi", + "bitflags 2.4.0", + "crossterm_winapi", + "libc", + "mio", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", ] [[package]] @@ -220,7 +221,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" dependencies = [ - "winapi", + "winapi", ] [[package]] @@ -229,13 +230,13 @@ version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2 0.4.9", - "winapi", + "curl-sys", + "libc", + "openssl-probe", + "openssl-sys", + "schannel", + "socket2 0.4.9", + "winapi", ] [[package]] @@ -244,13 +245,13 @@ version = "0.4.66+curl-8.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70c44a72e830f0e40ad90dda8a6ab6ed6314d39776599a58a2e5e37fbc6db5b9" dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "windows-sys 0.48.0", + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", + "windows-sys 0.48.0", ] [[package]] @@ -265,9 +266,9 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", ] [[package]] @@ -276,8 +277,8 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" dependencies = [ - "cc", - "libc", + "cc", + "libc", ] [[package]] @@ -304,7 +305,7 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ - "percent-encoding", + "percent-encoding", ] [[package]] @@ -313,13 +314,13 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", ] [[package]] @@ -328,8 +329,8 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ - "futures-core", - "futures-sink", + "futures-core", + "futures-sink", ] [[package]] @@ -344,9 +345,9 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ - "futures-core", - "futures-task", - "futures-util", + "futures-core", + "futures-task", + "futures-util", ] [[package]] @@ -361,9 +362,9 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -384,16 +385,16 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", ] [[package]] @@ -402,9 +403,9 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ - "cfg-if", - "libc", - "wasi", + "cfg-if", + "libc", + "wasi", ] [[package]] @@ -419,17 +420,17 @@ version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", ] [[package]] @@ -444,8 +445,8 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" dependencies = [ - "ahash", - "allocator-api2", + "ahash", + "allocator-api2", ] [[package]] @@ -454,7 +455,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.0", + "hashbrown 0.14.0", ] [[package]] @@ -475,9 +476,9 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ - "bytes", - "fnv", - "itoa", + "bytes", + "fnv", + "itoa", ] [[package]] @@ -486,9 +487,9 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ - "bytes", - "http", - "pin-project-lite", + "bytes", + "http", + "pin-project-lite", ] [[package]] @@ -509,22 +510,22 @@ version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.4.9", - "tokio", - "tower-service", - "tracing", - "want", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.4.9", + "tokio", + "tower-service", + "tracing", + "want", ] [[package]] @@ -533,12 +534,12 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows", + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows", ] [[package]] @@ -547,7 +548,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cc", + "cc", ] [[package]] @@ -556,8 +557,8 @@ version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ - "autocfg", - "hashbrown 0.12.3", + "autocfg", + "hashbrown 0.12.3", ] [[package]] @@ -572,9 +573,9 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi", - "rustix", - "windows-sys 0.48.0", + "hermit-abi", + "rustix", + "windows-sys 0.48.0", ] [[package]] @@ -583,7 +584,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ - "either", + "either", ] [[package]] @@ -598,7 +599,7 @@ version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ - "wasm-bindgen", + "wasm-bindgen", ] [[package]] @@ -619,9 +620,9 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" dependencies = [ - "cc", - "pkg-config", - "vcpkg", + "cc", + "pkg-config", + "vcpkg", ] [[package]] @@ -630,10 +631,10 @@ version = "1.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", + "cc", + "libc", + "pkg-config", + "vcpkg", ] [[package]] @@ -648,8 +649,8 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ - "autocfg", - "scopeguard", + "autocfg", + "scopeguard", ] [[package]] @@ -658,7 +659,7 @@ version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if", + "cfg-if", ] [[package]] @@ -673,7 +674,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ - "adler", + "adler", ] [[package]] @@ -682,10 +683,10 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.48.0", + "libc", + "log", + "wasi", + "windows-sys 0.48.0", ] [[package]] @@ -694,17 +695,17 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8d3038e23466858569c2d30a537f691fa0d53b51626630ae08262943e3bbb8b" dependencies = [ - "assert-json-diff", - "colored", - "futures", - "hyper", - "log", - "rand", - "regex", - "serde_json", - "serde_urlencoded", - "similar", - "tokio", + "assert-json-diff", + "colored", + "futures", + "hyper", + "log", + "rand", + "regex", + "serde_json", + "serde_urlencoded", + "similar", + "tokio", ] [[package]] @@ -713,7 +714,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ - "autocfg", + "autocfg", ] [[package]] @@ -722,8 +723,8 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", - "libc", + "hermit-abi", + "libc", ] [[package]] @@ -732,7 +733,7 @@ version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ - "memchr", + "memchr", ] [[package]] @@ -753,10 +754,10 @@ version = "0.9.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db7e971c2c2bba161b2d2fdf37080177eff520b3bc044787c7f1f5f9e78d869b" dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", + "cc", + "libc", + "pkg-config", + "vcpkg", ] [[package]] @@ -765,8 +766,8 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ - "lock_api", - "parking_lot_core", + "lock_api", + "parking_lot_core", ] [[package]] @@ -775,11 +776,11 @@ 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 0.42.0", + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys 0.42.0", ] [[package]] @@ -824,7 +825,7 @@ version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ - "unicode-ident", + "unicode-ident", ] [[package]] @@ -833,7 +834,7 @@ version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ - "proc-macro2", + "proc-macro2", ] [[package]] @@ -842,9 +843,9 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "libc", - "rand_chacha", - "rand_core", + "libc", + "rand_chacha", + "rand_core", ] [[package]] @@ -853,8 +854,8 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ - "ppv-lite86", - "rand_core", + "ppv-lite86", + "rand_core", ] [[package]] @@ -863,7 +864,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom", ] [[package]] @@ -872,11 +873,11 @@ version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcc0d032bccba900ee32151ec0265667535c230169f5a011154cdcd984e16829" dependencies = [ - "bitflags 1.3.2", - "cassowary", - "crossterm 0.26.1", - "unicode-segmentation", - "unicode-width", + "bitflags 1.3.2", + "cassowary", + "crossterm 0.26.1", + "unicode-segmentation", + "unicode-width", ] [[package]] @@ -885,15 +886,15 @@ version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e2e4cd95294a85c3b4446e63ef054eea43e0205b1fd60120c16b74ff7ff96ad" dependencies = [ - "bitflags 2.4.0", - "cassowary", - "crossterm 0.27.0", - "indoc", - "itertools", - "paste", - "strum", - "unicode-segmentation", - "unicode-width", + "bitflags 2.4.0", + "cassowary", + "crossterm 0.27.0", + "indoc", + "itertools", + "paste", + "strum", + "unicode-segmentation", + "unicode-width", ] [[package]] @@ -902,7 +903,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.3.2", ] [[package]] @@ -911,10 +912,10 @@ version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", ] [[package]] @@ -923,9 +924,9 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", + "aho-corasick", + "memchr", + "regex-syntax", ] [[package]] @@ -940,12 +941,12 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" dependencies = [ - "bitflags 2.4.0", - "fallible-iterator", - "fallible-streaming-iterator", - "hashlink", - "libsqlite3-sys", - "smallvec", + "bitflags 2.4.0", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", ] [[package]] @@ -960,11 +961,11 @@ version = "0.38.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" dependencies = [ - "bitflags 2.4.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.48.0", + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", ] [[package]] @@ -985,7 +986,7 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.48.0", ] [[package]] @@ -1000,7 +1001,7 @@ version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ - "serde_derive", + "serde_derive", ] [[package]] @@ -1009,9 +1010,9 @@ version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1020,9 +1021,9 @@ version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ - "itoa", - "ryu", - "serde", + "itoa", + "ryu", + "serde", ] [[package]] @@ -1031,10 +1032,10 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", + "form_urlencoded", + "itoa", + "ryu", + "serde", ] [[package]] @@ -1043,8 +1044,8 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" dependencies = [ - "libc", - "signal-hook-registry", + "libc", + "signal-hook-registry", ] [[package]] @@ -1053,9 +1054,9 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" dependencies = [ - "libc", - "mio", - "signal-hook", + "libc", + "mio", + "signal-hook", ] [[package]] @@ -1064,7 +1065,7 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ - "libc", + "libc", ] [[package]] @@ -1079,7 +1080,7 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ - "autocfg", + "autocfg", ] [[package]] @@ -1094,8 +1095,8 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ - "libc", - "winapi", + "libc", + "winapi", ] [[package]] @@ -1104,8 +1105,8 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" dependencies = [ - "libc", - "windows-sys 0.48.0", + "libc", + "windows-sys 0.48.0", ] [[package]] @@ -1114,7 +1115,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" dependencies = [ - "strum_macros", + "strum_macros", ] [[package]] @@ -1123,11 +1124,11 @@ version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn", + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", ] [[package]] @@ -1136,9 +1137,9 @@ version = "2.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] @@ -1147,17 +1148,17 @@ version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2 0.5.4", - "tokio-macros", - "windows-sys 0.48.0", + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.4", + "tokio-macros", + "windows-sys 0.48.0", ] [[package]] @@ -1166,9 +1167,9 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1177,12 +1178,12 @@ version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", ] [[package]] @@ -1197,9 +1198,9 @@ version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-core", + "cfg-if", + "pin-project-lite", + "tracing-core", ] [[package]] @@ -1208,7 +1209,7 @@ version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ - "once_cell", + "once_cell", ] [[package]] @@ -1223,8 +1224,8 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3e785f863a3af4c800a2a669d0b64c879b538738e352607e2624d03f868dc01" dependencies = [ - "crossterm 0.27.0", - "unicode-width", + "crossterm 0.27.0", + "unicode-width", ] [[package]] @@ -1233,8 +1234,8 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e06dbcd876f84929a9d00589c71d43e097ecdd5f775bdb5c843ce71cfc441a7" dependencies = [ - "crossterm 0.26.1", - "ratatui 0.20.1", + "crossterm 0.26.1", + "ratatui 0.20.1", ] [[package]] @@ -1273,7 +1274,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "try-lock", + "try-lock", ] [[package]] @@ -1288,8 +1289,8 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ - "cfg-if", - "wasm-bindgen-macro", + "cfg-if", + "wasm-bindgen-macro", ] [[package]] @@ -1298,13 +1299,13 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", ] [[package]] @@ -1313,8 +1314,8 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ - "quote", - "wasm-bindgen-macro-support", + "quote", + "wasm-bindgen-macro-support", ] [[package]] @@ -1323,11 +1324,11 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", ] [[package]] @@ -1342,8 +1343,8 @@ 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", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] @@ -1364,7 +1365,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets", + "windows-targets", ] [[package]] @@ -1373,13 +1374,13 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm 0.42.0", - "windows_aarch64_msvc 0.42.0", - "windows_i686_gnu 0.42.0", - "windows_i686_msvc 0.42.0", - "windows_x86_64_gnu 0.42.0", - "windows_x86_64_gnullvm 0.42.0", - "windows_x86_64_msvc 0.42.0", + "windows_aarch64_gnullvm 0.42.0", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm 0.42.0", + "windows_x86_64_msvc 0.42.0", ] [[package]] @@ -1388,7 +1389,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets", ] [[package]] @@ -1397,13 +1398,13 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 3452061..f3dc56a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,8 @@ tui-widget-list = "0.2.2" lazy_static = "1.4.0" rusqlite = { version = "0.29.0", features = ["bundled"] } serde_json = "1.0.107" -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"] } chrono = "0.4.31" curl = "0.4.44" mockito = "1.2.0" +regex = "1.9.5" diff --git a/output.txt b/output.txt deleted file mode 100644 index c7620a3..0000000 --- a/output.txt +++ /dev/null @@ -1 +0,0 @@ -This is a response \ No newline at end of file diff --git a/scripts/win64-wget.ps1 b/scripts/win64-wget.ps1 index e36ff37..4d368ea 100644 --- a/scripts/win64-wget.ps1 +++ b/scripts/win64-wget.ps1 @@ -21,7 +21,7 @@ function Invoke-Recursive-WebRequest( # if url is not provided exit with an error message if (-not$url) { - Write "Invoke-Recursive-WebRequest requires a url parameter" + Write-Error "Invoke-Recursive-WebRequest requires a url parameter" return } @@ -34,7 +34,7 @@ function Invoke-Recursive-WebRequest( #if output file is not provided exit with an error message if (-not$outputfile) { - Write "Invoke-Recursive-WebRequest requires an outputfile parameter" + Write-Error "Invoke-Recursive-WebRequest requires an outputfile parameter" return } diff --git a/src/app.rs b/src/app.rs index 2d08c8e..47e26ec 100644 --- a/src/app.rs +++ b/src/app.rs @@ -108,7 +108,8 @@ impl<'a> App<'_> { } pub fn move_cursor_down(&mut self) { - if self.items.is_empty() || self.cursor >= self.items.len() { + // Lorenzo: I fixed a bug here with -1, where the cursor would roll off the screen. + if self.items.is_empty() || self.cursor >= self.items.len() - 1 { return; } if let Some(res) = self.cursor.checked_add(1) { diff --git a/src/display/inputopt.rs b/src/display/inputopt.rs index 21a1078..6d85084 100644 --- a/src/display/inputopt.rs +++ b/src/display/inputopt.rs @@ -16,7 +16,7 @@ impl InputOpt { pub fn to_string(&self) -> String { match self { InputOpt::URL => "URL", - InputOpt::Headers => "Headers", + InputOpt::Headers => "Header", InputOpt::Output => "Output", InputOpt::RequestBody => "Request Body", InputOpt::RecursiveDownload => "Recursive Download", diff --git a/src/display/menuopts.rs b/src/display/menuopts.rs index 1a1d20e..d51c3d8 100644 --- a/src/display/menuopts.rs +++ b/src/display/menuopts.rs @@ -6,11 +6,12 @@ use lazy_static::lazy_static; lazy_static! { - pub static ref MAIN_MENU_OPTIONS: [&'static str; 4] = [ + pub static ref MAIN_MENU_OPTIONS: [&'static str; 5] = [ "Build and send an HTTP request\n \n", "Download a remote file or directory\n \n", "View my stored API keys\n \n", "View or execute my saved commands\n \n", + "Debug Menu. \n \n", ]; pub static ref REQUEST_MENU_OPTIONS: [&'static str; 8] = [ "Add a URL\n \n", @@ -66,4 +67,6 @@ lazy_static! { "View my saved commands\n \n", "Delete a saved command\n \n", ]; + pub static ref DEBUG_MENU_OPTIONS: [&'static str; 2] = + ["Back...\n \n", "URL Input Screen Debug \n \n"]; } diff --git a/src/events/handler.rs b/src/events/handler.rs index 259724c..a3b28c9 100644 --- a/src/events/handler.rs +++ b/src/events/handler.rs @@ -21,6 +21,12 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> { app.quit(); } } + KeyCode::Esc => { + app.go_back_screen(); // Escape Should Bring You Back + if app.input.value().len() > 0 { + app.input.reset(); // If we leave the page, we should clear the input buffer + } + } // Other handlers you could add here. KeyCode::Up => { app.move_cursor_up(); diff --git a/src/request/command.rs b/src/request/command.rs index 6e3bae0..5351ccf 100644 --- a/src/request/command.rs +++ b/src/request/command.rs @@ -10,9 +10,7 @@ pub enum Command<'a> { } impl<'a> Command<'a> { - pub fn default(curl: Curl<'a>) -> Self { - Command::Curl(curl) - } + // Im gonna fix this. We should be implmenting the default trait for Command pub fn set_method(&mut self, method: String) { match method.as_str() { @@ -150,3 +148,9 @@ impl<'a> Command<'a> { .to_string() } } + +impl<'a> Default for Command<'a> { + fn default() -> Self { + Command::Curl(Curl::new()) + } +} diff --git a/src/request/wget.rs b/src/request/wget.rs index ff59850..68a7192 100644 --- a/src/request/wget.rs +++ b/src/request/wget.rs @@ -21,19 +21,34 @@ impl Wget { } } + #[cfg(target_os = "windows")] + pub fn new() -> Self { + Wget { + cmd: String::from("powershell.exe -NoLogo -NoProfile -ExecutionPolicy Unrestricted -File scripts\\win64-wget.ps1"), + rec_level: 0, + url: String::new(), + auth: None, + output: String::new(), + response: None, + } + } + #[cfg(target_os = "windows")] pub fn build_string(&mut self) { if self.has_url() { if !self.cmd.as_bytes()[self.cmd.len() - 1].is_ascii_whitespace() { self.cmd.push(' '); } + self.cmd.push_str("-url"); + self.cmd.push(' '); self.cmd.push_str(self.url.as_str()); } if self.has_rec() { if !self.cmd.as_bytes()[self.cmd.len() - 1].is_ascii_whitespace() { self.cmd.push(' '); } - self.cmd.push_str(format!("-r {}", self.rec_level).as_str()); + self.cmd + .push_str(format!("-depth {}", self.rec_level).as_str()); } if self.has_auth() { if !self.cmd.as_bytes()[self.cmd.len() - 1].is_ascii_whitespace() { @@ -45,7 +60,8 @@ impl Wget { if !self.cmd.as_bytes()[self.cmd.len() - 1].is_ascii_whitespace() { self.cmd.push(' '); } - self.cmd.push_str(format!("-O {}", self.output).as_str()); + self.cmd + .push_str(format!("-outputfile {}", self.output).as_str()); } self.cmd = self.cmd.trim().to_string(); } @@ -136,32 +152,33 @@ impl Wget { Err(String::from_utf8(output.stderr).unwrap()) } } -} - -pub mod tests { - use crate::request::wget::Wget; - #[test] #[cfg(target_os = "windows")] - pub fn execute(&mut self) -> Result { - let output = std::process::Command::new("powershell.exe") - .arg("-NoLogo") - .arg("-NoProfile") - .arg("-ExecutionPolicy") - .arg("Unrestricted") - .arg("-File") - .arg("scripts\\win64-wget.ps1") - .arg(self.cmd.clone()) + pub fn execute(&mut self) -> Result<(), String> { + let commands = self.cmd.split(" ").collect::>(); + let args = commands[7..].join(" "); + + let output = std::process::Command::new(commands[0]) + .arg(commands[1]) // -NoLogo + .arg(commands[2]) // -NoProfile + .arg(commands[3]) // -ExecutionPolicy + .arg(commands[4]) // unrestricted + .arg(commands[5]) // -File + .arg(commands[6]) // scripts\\win64-wget.ps1 + .arg(args) // Rest Of The Command Arguments .output() .expect("failed to execute process"); - let outstr = format!("{:?}", output); - println!("{}", outstr); if output.status.success() { - Ok(String::from_utf8(output.stdout).unwrap()) + self.response = Some(String::from_utf8(output.stdout).unwrap()); + Ok(()) } else { Err(String::from_utf8(output.stderr).unwrap()) } } +} + +mod tests { + use crate::request::wget::Wget; #[test] #[cfg(any(target_os = "linux", target_os = "macos"))] @@ -176,7 +193,7 @@ pub mod tests { #[cfg(target_os = "windows")] fn test_new_wget() { let wget = Wget::new(); - assert_eq!("", wget.cmd); + assert_eq!("powershell.exe -NoLogo -NoProfile -ExecutionPolicy Unrestricted -File scripts\\win64-wget.ps1", wget.cmd); assert_eq!("", wget.url); assert_eq!("", wget.output); } @@ -194,9 +211,9 @@ pub mod tests { #[cfg(target_os = "windows")] fn test_set_url_win() { let mut wget = Wget::new(); - wget.set_url(String::from("http://www.google.com")); + wget.set_url("http://www.google.com"); wget.build_string(); - assert_eq!("-url http://www.google.com", wget.cmd); + assert_eq!("powershell.exe -NoLogo -NoProfile -ExecutionPolicy Unrestricted -File scripts\\win64-wget.ps1 -url http://www.google.com", wget.cmd); } #[test] @@ -212,9 +229,9 @@ pub mod tests { #[cfg(target_os = "windows")] fn test_set_output() { let mut wget = Wget::new(); - wget.set_output(String::from("output")); + wget.set_output("output"); wget.build_string(); - assert_eq!("-outputfile output", wget.cmd); + assert_eq!("powershell.exe -NoLogo -NoProfile -ExecutionPolicy Unrestricted -File scripts\\win64-wget.ps1 -outputfile output", wget.cmd); } #[test] @@ -232,7 +249,7 @@ pub mod tests { let mut wget = Wget::new(); wget.add_auth("usr", "pwd"); wget.build_string(); - assert_eq!("-username usr -password pwd", wget.cmd); + assert_eq!("powershell.exe -NoLogo -NoProfile -ExecutionPolicy Unrestricted -File scripts\\win64-wget.ps1 -username usr -password pwd", wget.cmd); } #[test] @@ -254,11 +271,11 @@ pub mod tests { fn test_build_string() { let mut wget = Wget::new(); wget.add_auth("usr", "pwd"); - wget.set_url(String::from("http://www.google.com")); - wget.set_output(String::from("output")); + wget.set_url("http://www.google.com"); + wget.set_output("output"); wget.build_string(); assert_eq!( - "-url http://www.google.com -username usr -password pwd -outputfile output", + "powershell.exe -NoLogo -NoProfile -ExecutionPolicy Unrestricted -File scripts\\win64-wget.ps1 -url http://www.google.com -username usr -password pwd -outputfile output", wget.cmd ); } @@ -273,6 +290,7 @@ pub mod tests { } #[test] + #[cfg(any(target_os = "linux", target_os = "macos"))] fn test_execute() { let mut wget = Wget::new(); wget.set_url("http://www.google.com"); @@ -285,11 +303,12 @@ pub mod tests { std::fs::remove_file("output").unwrap(); } + #[test] #[cfg(target_os = "windows")] fn test_increase_rec_level() { let mut wget = Wget::new(); wget.set_rec_download_level(2); - assert_eq!("", wget.cmd); + assert_eq!("powershell.exe -NoLogo -NoProfile -ExecutionPolicy Unrestricted -File scripts\\win64-wget.ps1", wget.cmd); assert_eq!(2, wget.rec_level); } @@ -297,10 +316,10 @@ pub mod tests { #[cfg(target_os = "windows")] fn test_execute() { let mut wget = Wget::new(); - wget.set_url(String::from("http://www.google.com")); - wget.set_output(String::from("output")); + wget.set_url("http://www.google.com"); + wget.set_output("output"); wget.build_string(); - assert_eq!("-url http://www.google.com -outputfile output", wget.cmd); + assert_eq!("powershell.exe -NoLogo -NoProfile -ExecutionPolicy Unrestricted -File scripts\\win64-wget.ps1 -url http://www.google.com -outputfile output", wget.cmd); let result = wget.execute(); assert_eq!(true, result.is_ok()); assert!(std::fs::metadata("output.txt").is_ok()); diff --git a/src/screens/auth.rs b/src/screens/auth.rs new file mode 100644 index 0000000..7f2bb7d --- /dev/null +++ b/src/screens/auth.rs @@ -0,0 +1,48 @@ +use tui::backend::Backend; +use tui::widgets::ListState; +use tui::Frame; + +use crate::app::App; +use crate::display::inputopt::InputOpt; +use crate::request::curl::AuthKind; +use crate::screens::screen::Screen; +use crate::ui::widgets::boxes::default_rect; +use crate::ui::widgets::menu::menu_widget; + +pub fn handle_authentication_screen(app: &mut App, frame: &mut Frame<'_, B>) { + let area = default_rect(frame.size()); + let new_list = app.current_screen.get_list(); + let mut state = ListState::with_selected(ListState::default(), Some(app.cursor)); + app.items = app.current_screen.get_opts(); + app.state = Some(state.clone()); + app.state.as_mut().unwrap().select(Some(app.cursor)); + frame.set_cursor(0, app.cursor as u16); + frame.render_stateful_widget(new_list, area, &mut state); + frame.render_widget(menu_widget(), frame.size()); + if let Some(num) = app.selected { + match num { + 0 => app.goto_screen(Screen::InputMenu(InputOpt::Auth(AuthKind::Basic( + String::new(), + )))), + 1 => app.goto_screen(Screen::InputMenu(InputOpt::Auth(AuthKind::Bearer( + String::new(), + )))), + 2 => app.goto_screen(Screen::InputMenu(InputOpt::Auth(AuthKind::Digest( + String::new(), + )))), + 3 => app.goto_screen(Screen::InputMenu(InputOpt::Auth(AuthKind::AwsSigv4( + String::new(), + )))), + 4 => app.goto_screen(Screen::InputMenu(InputOpt::Auth(AuthKind::Spnego( + String::new(), + )))), + 5 => app.goto_screen(Screen::InputMenu(InputOpt::Auth(AuthKind::Kerberos( + String::new(), + )))), + 6 => app.goto_screen(Screen::InputMenu(InputOpt::Auth(AuthKind::Ntlm( + String::new(), + )))), + _ => {} + } + } +} diff --git a/src/screens/debug.rs b/src/screens/debug.rs new file mode 100644 index 0000000..7a01ad8 --- /dev/null +++ b/src/screens/debug.rs @@ -0,0 +1,34 @@ +use tui::backend::Backend; +use tui::widgets::ListState; +use tui::Frame; + +use crate::app::App; +use crate::screens::screen::Screen; +use crate::ui::widgets::boxes::centered_rect; +use crate::ui::widgets::menu::menu_widget; + +pub fn handle_debug_screen(app: &mut App, frame: &mut Frame<'_, B>) { + let menu_options = app.current_screen.get_list(); + let area = centered_rect(70, 60, frame.size()); + + let mut state = ListState::with_selected(ListState::default(), Some(app.cursor)); + + app.state = Some(state.clone()); + app.state.as_mut().unwrap().select(Some(app.cursor)); + + frame.set_cursor(0, app.cursor as u16); + frame.render_stateful_widget(menu_options, area, &mut state); + frame.render_widget(menu_widget(), frame.size()); + + match app.selected { + Some(0) => { + // Back To Home + app.goto_screen(Screen::Home); // Back + } + Some(1) => { + // Test Single Line Input Screen + app.goto_screen(Screen::URLInput); + } + _ => {} + } +} diff --git a/src/screens/downloads.rs b/src/screens/downloads.rs new file mode 100644 index 0000000..c4e2785 --- /dev/null +++ b/src/screens/downloads.rs @@ -0,0 +1,54 @@ +use tui::backend::Backend; +use tui::widgets::ListState; +use tui::Frame; + +use crate::app::App; +use crate::display::inputopt::InputOpt; +use crate::screens::screen::Screen; +use crate::ui::widgets::boxes::default_rect; +use crate::ui::widgets::menu::menu_widget; + +pub fn handle_downloads_screen(app: &mut App, frame: &mut Frame<'_, B>) { + let area = default_rect(frame.size()); + let list = app.current_screen.get_list(); + let mut state = ListState::with_selected(ListState::default(), Some(app.cursor)); + app.items = app.current_screen.get_opts(); + app.state = Some(state.clone()); + app.state.as_mut().unwrap().select(Some(app.cursor)); + frame.set_cursor(0, app.cursor as u16); + frame.render_stateful_widget(list, area, &mut state); + frame.render_widget(menu_widget(), frame.size()); + + if let Some(num) = app.selected { + match num { + // Setting Recursion level + 0 => { + app.goto_screen(Screen::InputMenu(InputOpt::RecursiveDownload)); + app.selected = None; + } + // Add URL of download + 1 => { + app.goto_screen(Screen::InputMenu(InputOpt::URL)); + app.selected = None; + } + // Add file name for output/download + 2 => { + app.goto_screen(Screen::InputMenu(InputOpt::Output)); + app.selected = None; + // Execute command + } + 3 => match app.command.as_mut().unwrap().execute() { + Ok(_) => { + if let Some(response) = app.command.as_ref().unwrap().get_response() { + app.response = Some(response.clone()); + app.goto_screen(Screen::Response(response)); + } + } + Err(e) => { + app.goto_screen(Screen::Error(e.to_string())); + } + }, + _ => {} + }; + } +} diff --git a/src/screens/home.rs b/src/screens/home.rs new file mode 100644 index 0000000..920ccc8 --- /dev/null +++ b/src/screens/home.rs @@ -0,0 +1,38 @@ +use tui::backend::Backend; +use tui::widgets::ListState; +use tui::Frame; + +use crate::app::App; +use crate::screens::screen::Screen; +use crate::ui::widgets::boxes::centered_rect; +use crate::ui::widgets::menu::menu_widget; + +pub fn handle_home_screen(app: &mut App, frame: &mut Frame<'_, B>) { + let new_list = app.current_screen.get_list(); + let area = centered_rect(70, 60, frame.size()); + let mut state = ListState::with_selected(ListState::default(), Some(app.cursor)); + app.state = Some(state.clone()); + app.state.as_mut().unwrap().select(Some(app.cursor)); + frame.set_cursor(0, app.cursor as u16); + frame.render_stateful_widget(new_list, area, &mut state); + frame.render_widget(menu_widget(), frame.size()); + match app.selected { + Some(0) => { + app.goto_screen(Screen::Method); + } + Some(1) => { + app.goto_screen(Screen::Downloads); + } + Some(2) => { + app.goto_screen(Screen::Keys); + } + Some(3) => { + app.goto_screen(Screen::Commands); + } + Some(4) => { + app.goto_screen(Screen::Debug); + } + Some(_) => {} + None => {} + } +} diff --git a/src/screens/input/input.rs b/src/screens/input/input.rs new file mode 100644 index 0000000..b04386c --- /dev/null +++ b/src/screens/input/input.rs @@ -0,0 +1,183 @@ +/// Renders a screen we can grab input from, pass in the appropriate designation for the input +pub fn render_input_screen(app: &mut App, frame: &mut Frame<'_, B>, opt: InputOpt) { + match opt { + InputOpt::URL => render_default_input(app, frame, opt), + InputOpt::Headers => render_headers_input(app, frame, opt), + InputOpt::RecursiveDownload => render_recursive_download_input(app, frame, opt), + _ => render_default_input(app, frame, opt), + } +} + +pub fn render_headers_input(app: &mut App, frame: &mut Frame<'_, B>, opt: InputOpt) { + let header_prompt = Text::from(Line::from( + "MUST be \"Key:Value\" pair and press Enter \n Example: Content-Type: application/json", + )); + render_input_with_prompt(app, frame, header_prompt, opt); +} + +pub fn render_input_with_prompt( + _app: &mut App, + frame: &mut Frame<'_, B>, + prompt: Text, + _opt: InputOpt, +) { + // Render the input with the provided prompt + let chunks = Layout::default() + .direction(Direction::Vertical) + .margin(2) + .constraints( + [ + Constraint::Length(1), + Constraint::Length(3), + Constraint::Min(1), + ] + .as_ref(), + ) + .split(frame.size()); + + let message = Paragraph::new(prompt); + frame.render_widget(message, chunks[0]); +} + +pub fn render_recursive_download_input( + app: &mut App, + frame: &mut Frame<'_, B>, + opt: InputOpt, +) { + let header_prompt = Text::from(Line::from( + "Enter the recursion level and press Enter \n Example: 2", + )); + render_input_with_prompt(app, frame, header_prompt, opt); +} + +pub fn render_default_input(app: &mut App, frame: &mut Frame<'_, B>, opt: InputOpt) { + let chunks = Layout::default() + .direction(Direction::Vertical) + .margin(2) + .constraints( + [ + Constraint::Length(1), + Constraint::Length(3), + Constraint::Min(1), + ] + .as_ref(), + ) + .split(frame.size()); + let (_msg, style) = match app.input_mode { + InputMode::Normal => ( + vec![ + Span::raw("Press "), + Span::styled("q", Style::default().add_modifier(Modifier::BOLD)), + Span::raw(" to exit, "), + Span::styled("i", Style::default().add_modifier(Modifier::BOLD)), + Span::raw(" to start editing."), + ], + Style::default().add_modifier(Modifier::RAPID_BLINK), + ), + InputMode::Editing => ( + vec![ + Span::raw("Press "), + Span::styled("Esc", Style::default().add_modifier(Modifier::BOLD)), + Span::raw(" to stop editing, "), + Span::styled("Enter", Style::default().add_modifier(Modifier::BOLD)), + Span::raw(" to submit."), + ], + Style::default(), + ), + }; + + let mut header_prompt = Text::from("Enter a value and press Enter"); + header_prompt.patch_style(style); + + render_input_with_prompt(app, frame, header_prompt, opt.clone()); + + let width = chunks[0].width.max(3) - 3; // keep 2 for borders and 1 for cursor + + let scroll = app.input.visual_scroll(width as usize); + let input = Paragraph::new(app.input.value()) + .style(match app.input_mode { + InputMode::Normal => Style::default(), + InputMode::Editing => Style::default().fg(Color::Yellow), + }) + .scroll((0, scroll as u16)) + .block(Block::default().borders(Borders::ALL).title("Input")); + frame.render_widget(input, chunks[1]); + match app.input_mode { + InputMode::Normal => {} + InputMode::Editing => frame.set_cursor( + chunks[1].x + ((app.input.visual_cursor()).max(scroll) - scroll) as u16 + 1, + chunks[1].y + 1, + ), + } + + if !app.messages.is_empty() { + match opt { + InputOpt::URL => { + app.command + .as_mut() + .unwrap() + .set_url(app.messages[0].clone()); + app.input_mode = InputMode::Normal; + app.add_display_option(DisplayOpts::URL(app.messages[0].clone())); + app.current_screen = Screen::RequestMenu(String::new()); + app.messages.remove(0); + } + + InputOpt::Headers => { + let headers = app + .messages + .get(0) + .unwrap() + .split(':') + .collect::>(); + let cpy = ( + String::from(headers[0].clone()), + String::from(headers[1].clone()), + ); + app.command + .as_mut() + .unwrap() + .set_headers(headers.iter().map(|x| x.to_string()).collect()); + app.add_display_option(DisplayOpts::Headers(cpy)); + app.current_screen = Screen::RequestMenu(String::new()); + app.messages.remove(0); + } + + InputOpt::Output => { + app.command + .as_mut() + .unwrap() + .set_outfile(app.messages[0].clone()); + app.add_display_option(DisplayOpts::Outfile(app.messages[0].clone())); + app.messages.remove(0); + app.goto_screen(Screen::RequestMenu(String::new())); + } + + InputOpt::Execute => { + // This means they have executed the command, and want to write to a file + app.command + .as_mut() + .unwrap() + .set_outfile(app.messages[0].clone()); + match app.command.as_mut().unwrap().write_output() { + Ok(_) => { + app.goto_screen(Screen::Success); + } + Err(e) => { + app.goto_screen(Screen::Error(e.to_string())); + } + } + app.goto_screen(Screen::Home); + } + + InputOpt::RecursiveDownload => { + let recursion_level = app.messages[0].parse::().unwrap(); + app.command + .as_mut() + .unwrap() + .set_rec_download_level(recursion_level); + } + _ => {} + } + } +} diff --git a/src/screens/input/mod.rs b/src/screens/input/mod.rs new file mode 100644 index 0000000..51f6397 --- /dev/null +++ b/src/screens/input/mod.rs @@ -0,0 +1,5 @@ +pub mod outputfile; +pub mod recursivedownload; +pub mod url; + +pub mod test; diff --git a/src/screens/input/outputfile.rs b/src/screens/input/outputfile.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/screens/input/outputfile.rs @@ -0,0 +1 @@ + diff --git a/src/screens/input/recursivedownload.rs b/src/screens/input/recursivedownload.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/screens/input/recursivedownload.rs @@ -0,0 +1 @@ + diff --git a/src/screens/input/test.rs b/src/screens/input/test.rs new file mode 100644 index 0000000..8d08e59 --- /dev/null +++ b/src/screens/input/test.rs @@ -0,0 +1,86 @@ +use std::rc::Rc; + +use tui::backend::Backend; +use tui::layout::{Constraint, Direction, Layout, Rect}; +use tui::style::{Color, Style}; +use tui::text::Text; +use tui::widgets::{Block, Borders, Paragraph}; +use tui::Frame; + +use crate::app::App; + +fn create_layout(frame: &mut Frame<'_, B>) -> (Rc<[Rect]>, Rc<[Rect]>, Rc<[Rect]>) { + let parent_chunks = Layout::default() + .direction(Direction::Vertical) + .constraints( + [ + Constraint::Length(3), // Title Area + Constraint::Length(3), // Input Area + Constraint::Min(1), + ] + .as_ref(), + ) + .split(frame.size()); + + let body_column_chunks = Layout::default() + .direction(Direction::Horizontal) + .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref()) + .split(parent_chunks[2]); + + let left_col_chunks = Layout::default() + .direction(Direction::Vertical) + .constraints( + [ + Constraint::Length(1), + Constraint::Length(3), + Constraint::Min(1), + ] + .as_ref(), + ) + .split(body_column_chunks[0]); + + let right_col_chunks = Layout::default() + .direction(Direction::Vertical) + .constraints( + [ + Constraint::Length(1), + Constraint::Length(3), + Constraint::Min(1), + ] + .as_ref(), + ) + .split(body_column_chunks[1]); + + (parent_chunks, right_col_chunks, left_col_chunks) +} + +fn create_screen_title<'a>(title_str: &'a str) -> Paragraph<'a> { + let title_block = Block::default().style(Style::default()); + + let title = Paragraph::new(Text::styled(title_str, Style::default().fg(Color::Green))) + .block(title_block); + title +} + +fn create_input_block<'a>(app: &'a mut App) -> Paragraph<'a> { + let input_block = Block::default() + .borders(Borders::ALL) + .style(Style::default()); + + let input = Paragraph::new(Text::styled( + app.input.value(), + Style::default().fg(Color::Green), + )) + .block(input_block); + input +} + +pub fn TextInput(app: &mut App, frame: &mut Frame<'_, B>) { + // Create Render Objects & Layout + let (parent_chunks, right_col_chunks, left_col_chunks) = create_layout(frame); + let title = create_screen_title("Test Title"); + let input = create_input_block(app); + // Render Widgets + frame.render_widget(title, parent_chunks[0]); // Title Widget + frame.render_widget(input, right_col_chunks[1]); // Input Widget +} diff --git a/src/screens/input/url.rs b/src/screens/input/url.rs new file mode 100644 index 0000000..5af8d7b --- /dev/null +++ b/src/screens/input/url.rs @@ -0,0 +1,57 @@ +use std::rc::Rc; + +use tui::layout::{Constraint, Direction, Layout, Rect}; +use tui::prelude::Backend; +use tui::style::{Color, Style}; +use tui::text::Text; +use tui::widgets::{Block, Borders, Paragraph}; +use tui::Frame; + +use crate::app::App; + +pub fn handle_url_input_screen(app: &mut App, frame: &mut Frame<'_, B>) { + let layout_chunks = create_layout(frame); + + let title_paragraph = create_screen_title("URL Input"); + let input_block = create_input_block(app); + + frame.render_widget(title_paragraph, layout_chunks[0]); + frame.render_widget(input_block, layout_chunks[1]); +} + +fn create_layout(frame: &mut Frame<'_, B>) -> Rc<[Rect]> { + let parent_chunks = Layout::default() + .direction(Direction::Vertical) + .margin(2) + .constraints( + [ + Constraint::Length(3), // Title Area + Constraint::Length(3), // Input Area + Constraint::Min(1), + ] + .as_ref(), + ) + .split(frame.size()); + + parent_chunks +} + +fn create_screen_title<'a>(title_str: &'a str) -> Paragraph<'a> { + let title_block = Block::default().style(Style::default()); + let title = Paragraph::new(Text::styled(title_str, Style::default().fg(Color::Green))) + .block(title_block); + title +} + +fn create_input_block<'a>(app: &'a mut App) -> Paragraph<'a> { + let title_block = Block::default() + .borders(Borders::ALL) + .style(Style::default()); + + let title = Paragraph::new(Text::styled( + app.input.value(), + Style::default().fg(Color::Green), + )) + .block(title_block); + title +} diff --git a/src/screens/keys.rs b/src/screens/keys.rs new file mode 100644 index 0000000..fd532f1 --- /dev/null +++ b/src/screens/keys.rs @@ -0,0 +1,40 @@ +use tui::backend::Backend; +use tui::layout::Alignment; +use tui::style::{Color, Style}; +use tui::widgets::{Block, BorderType, Borders, ListState, Paragraph}; +use tui::Frame; + +use crate::app::App; +use crate::ui::widgets::boxes::default_rect; + +pub fn handle_api_key_screen(app: &mut App, frame: &mut Frame<'_, B>) { + let area = default_rect(frame.size()); + let new_list = app.current_screen.get_list(); + let mut state = ListState::with_selected(ListState::default(), Some(app.cursor)); + if !app.items.is_empty() { + app.items.clear(); + } + app.items = app.current_screen.get_opts(); + app.state = Some(state.clone()); + app.state.as_mut().unwrap().select(Some(app.cursor)); + + frame.set_cursor(0, app.cursor as u16); + frame.render_stateful_widget(new_list, area, &mut state); + frame.render_widget(api_key_paragraph(), frame.size()); +} + +pub fn api_key_paragraph() -> Paragraph<'static> { + Paragraph::new( + "Create / Edit / Delete API Keys and tokens.\n + Press q to exit \n Press Enter to select \n Please select a Menu item\n", + ) + .block( + Block::default() + .title("API Key Manager") + .title_alignment(Alignment::Center) + .borders(Borders::ALL) + .border_type(BorderType::Rounded), + ) + .style(Style::default().fg(Color::Cyan).bg(Color::Black)) + .alignment(Alignment::Center) +} diff --git a/src/screens/method.rs b/src/screens/method.rs new file mode 100644 index 0000000..9f8eafe --- /dev/null +++ b/src/screens/method.rs @@ -0,0 +1,37 @@ +use tui::backend::Backend; +use tui::widgets::ListState; +use tui::Frame; + +use crate::app::App; +use crate::display::menuopts::METHOD_MENU_OPTIONS; +use crate::request::command::Command; +use crate::screens::screen::Screen; +use crate::ui::widgets::boxes::default_rect; +use crate::ui::widgets::menu::menu_widget; + +pub fn handle_method_select_screen(app: &mut App, frame: &mut Frame<'_, B>) { + // Added this command init here because it was causing a panic because it wasnt initialized. + app.command = Some(Command::default()); + + let area = default_rect(frame.size()); + let new_list = app.current_screen.get_list(); + let mut state = ListState::with_selected(ListState::default(), Some(app.cursor)); + app.items = app.current_screen.get_opts(); + app.state = Some(state.clone()); + app.state.as_mut().unwrap().select(Some(app.cursor)); + frame.set_cursor(0, app.cursor as u16); + frame.render_stateful_widget(new_list, area, &mut state); + frame.render_widget(menu_widget(), frame.size()); + match app.selected { + Some(num) => { + app.command + .as_mut() + .unwrap() + .set_method(String::from(METHOD_MENU_OPTIONS[num])); // safe index + app.goto_screen(Screen::RequestMenu(String::from( + METHOD_MENU_OPTIONS[num].clone(), + ))); + } + None => {} + } +} diff --git a/src/screens/mod.rs b/src/screens/mod.rs index 63ac656..2cddacf 100644 --- a/src/screens/mod.rs +++ b/src/screens/mod.rs @@ -1 +1,34 @@ pub mod screen; + +// Home Screen +pub mod home; + +// API Keys +pub mod keys; + +// Downloads Screen +pub mod downloads; + +// Method Select Screens +pub mod method; + +// Request Select Screens +pub mod request; + +// Success Screen +pub mod success; + +// Response Screen +pub mod response; + +// View Body Screen +pub mod viewbody; + +// Debug Menu Screen +pub mod debug; + +// All Input Type Screens +pub mod input; + +// Auth Screen +pub mod auth; diff --git a/src/screens/request.rs b/src/screens/request.rs new file mode 100644 index 0000000..3635e5c --- /dev/null +++ b/src/screens/request.rs @@ -0,0 +1,78 @@ +use tui::backend::Backend; +use tui::widgets::ListState; +use tui::Frame; + +use crate::app::App; +use crate::display::displayopts::DisplayOpts; +use crate::display::inputopt::InputOpt; +use crate::screens::screen::Screen; +use crate::ui::widgets::boxes::default_rect; +use crate::ui::widgets::menu::menu_widget; + +pub fn handle_request_menu_screen(app: &mut App, frame: &mut Frame<'_, B>) { + let area = default_rect(frame.size()); + let new_list = app.current_screen.get_list(); + let mut state = ListState::with_selected(ListState::default(), Some(app.cursor)); + if !app.items.is_empty() { + app.items.clear(); + } + app.items = app.current_screen.get_opts(); + app.state = Some(state.clone()); + app.state.as_mut().unwrap().select(Some(app.cursor)); + frame.set_cursor(0, app.cursor as u16); + frame.render_stateful_widget(new_list, area, &mut state); + frame.render_widget(menu_widget(), frame.size()); + match app.selected { + Some(num) => match num { + // Add a URL, + 0 => app.goto_screen(Screen::InputMenu(InputOpt::URL)), + // Auth + 1 => app.goto_screen(Screen::Authentication), + // Headers + 2 => app.goto_screen(Screen::InputMenu(InputOpt::Headers)), + // Verbose + 3 => { + if app.opts.contains(&DisplayOpts::Verbose) { + app.opts.retain(|x| x != &DisplayOpts::Verbose); + app.command.as_mut().unwrap().set_verbose(false); + } else { + app.add_display_option(DisplayOpts::Verbose); + app.command.as_mut().unwrap().set_verbose(true); + } + app.selected = None; + } + // Output file, + 4 => { + app.goto_screen(Screen::InputMenu(InputOpt::Output)); + app.selected = None; + } + // Request Body + 5 => { + app.goto_screen(Screen::InputMenu(InputOpt::RequestBody)); + app.selected = None; + } + // Save this command + 6 => { + app.goto_screen(Screen::Commands); + app.selected = None; + } + // Execute command + 7 => match app.command.as_mut().unwrap().execute() { + Ok(()) => { + if app.command.as_ref().unwrap().get_response().is_some() { + app.response = app.command.as_ref().unwrap().get_response().clone(); + app.goto_screen(Screen::Response(app.response.clone().unwrap())); + } else { + app.goto_screen(Screen::Error("Unable To Retreve Response...".to_string())); + } + } + Err(e) => { + app.goto_screen(Screen::Error(e.to_string())); + } + }, + + _ => {} + }, + None => {} + } +} diff --git a/src/screens/response.rs b/src/screens/response.rs new file mode 100644 index 0000000..95376f6 --- /dev/null +++ b/src/screens/response.rs @@ -0,0 +1,45 @@ +use tui::backend::Backend; +use tui::layout::Alignment; +use tui::style::{Color, Style}; +use tui::text::Text; +use tui::widgets::{ListState, Paragraph}; +use tui::Frame; + +use crate::app::App; +use crate::display::inputopt::InputOpt; +use crate::screens::screen::Screen; +use crate::ui::widgets::boxes::{default_rect, small_alert_box}; + +pub fn handle_response_screen(app: &mut App, frame: &mut Frame<'_, B>, resp: String) { + let area = default_rect(small_alert_box(frame.size())); + let new_list = app.current_screen.get_list(); + let mut state = ListState::with_selected(ListState::default(), Some(app.cursor)); + let paragraph = Paragraph::new(Text::from(resp.as_str())) + .style(Style::default().fg(Color::Yellow).bg(Color::Black)) + .alignment(Alignment::Center); + if !app.items.is_empty() { + app.items.clear(); + } + app.items = app.current_screen.get_opts(); + app.state = Some(state.clone()); + app.state.as_mut().unwrap().select(Some(app.cursor)); + frame.set_cursor(0, app.cursor as u16); + frame.render_stateful_widget(new_list, area, &mut state); + let area_2 = small_alert_box(frame.size()); + frame.render_widget(paragraph, area_2); + match app.selected { + Some(num) => match num { + 0 => { + app.goto_screen(Screen::InputMenu(InputOpt::Output)); + } + 1 => { + app.goto_screen(Screen::Commands); + } + 2 => { + app.goto_screen(Screen::ViewBody); + } + _ => {} + }, + None => {} + } +} diff --git a/src/screens/screen.rs b/src/screens/screen.rs index 9e37bdd..e1deaf6 100644 --- a/src/screens/screen.rs +++ b/src/screens/screen.rs @@ -7,9 +7,9 @@ use tui::widgets::{Block, Borders, List, ListItem}; use crate::display::inputopt::InputOpt; use crate::display::menuopts::{ - API_KEY_MENU_OPTIONS, AUTHENTICATION_MENU_OPTIONS, DOWNLOAD_MENU_OPTIONS, INPUT_MENU_OPTIONS, - MAIN_MENU_OPTIONS, METHOD_MENU_OPTIONS, REQUEST_MENU_OPTIONS, RESPONSE_MENU_OPTIONS, - SAVED_COMMAND_OPTIONS, + API_KEY_MENU_OPTIONS, AUTHENTICATION_MENU_OPTIONS, DEBUG_MENU_OPTIONS, DOWNLOAD_MENU_OPTIONS, + INPUT_MENU_OPTIONS, MAIN_MENU_OPTIONS, METHOD_MENU_OPTIONS, REQUEST_MENU_OPTIONS, + RESPONSE_MENU_OPTIONS, SAVED_COMMAND_OPTIONS, }; #[derive(Debug, PartialEq, Clone)] @@ -27,6 +27,8 @@ pub enum Screen { Commands, Error(String), ViewBody, + Debug, + URLInput, } impl<'a> Screen { @@ -100,12 +102,21 @@ impl<'a> Screen { vec![ListItem::new("View Body").style(Style::default().fg(Color::Green))] } Screen::Downloads => { - return DOWNLOAD_MENU_OPTIONS .iter() .map(|i| ListItem::new(*i)) .collect(); } + Screen::Debug => { + // Menu For Debug Screens + return DEBUG_MENU_OPTIONS + .iter() + .map(|i| ListItem::new(*i)) + .collect(); + } + Screen::URLInput => { + vec![ListItem::new("URL Input").style(Style::default().fg(Color::Green))] + } } } @@ -136,6 +147,8 @@ impl<'a> Screen { Screen::Error(_) => "Error", Screen::ViewBody => "View response body", Screen::Downloads => "Downloads", + Screen::Debug => "Debug Menu", + Screen::URLInput => "URL Input", } .to_string() } diff --git a/src/screens/success.rs b/src/screens/success.rs new file mode 100644 index 0000000..55ba5b5 --- /dev/null +++ b/src/screens/success.rs @@ -0,0 +1,13 @@ +use tui::backend::Backend; +use tui::Frame; + +use crate::app::App; +use crate::ui::widgets::boxes::default_rect; +use crate::ui::widgets::menu::menu_widget; + +pub fn handle_success_screen(app: &mut App, frame: &mut Frame<'_, B>) { + let area = default_rect(frame.size()); + app.items = app.current_screen.get_opts(); + frame.set_cursor(0, app.cursor as u16); + frame.render_widget(menu_widget(), area); +} diff --git a/src/screens/viewbody.rs b/src/screens/viewbody.rs new file mode 100644 index 0000000..85a58e2 --- /dev/null +++ b/src/screens/viewbody.rs @@ -0,0 +1,20 @@ +use tui::backend::Backend; +use tui::layout::Alignment; +use tui::style::{Color, Style}; +use tui::text::Text; +use tui::widgets::Paragraph; +use tui::Frame; + +use crate::app::App; +use crate::ui::widgets::boxes::small_rect; + +pub fn handle_view_body_screen(app: &mut App, frame: &mut Frame<'_, B>) { + // screen with only the body of the response + app.items.clear(); + let area = small_rect(frame.size()); + let response = app.response.clone().unwrap(); + let paragraph = Paragraph::new(Text::from(response.as_str())) + .style(Style::default().fg(Color::Yellow).bg(Color::Black)) + .alignment(Alignment::Center); + frame.render_widget(paragraph, area); +} diff --git a/src/ui/mod.rs b/src/ui/mod.rs index ff8ab2f..1b27980 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -2,3 +2,4 @@ pub mod tui; pub mod render; +pub mod widgets; diff --git a/src/ui/render.rs b/src/ui/render.rs index dbee6d9..fc73f87 100644 --- a/src/ui/render.rs +++ b/src/ui/render.rs @@ -6,16 +6,27 @@ use tui::{ widgets::{Block, BorderType, Borders, ListState, Paragraph}, Frame, }; - +use crate::request::wget::Wget; +use crate::request::curl::Curl; +use crate::display::menuopts::METHOD_MENU_OPTIONS; use crate::app::{App, InputMode}; use crate::display::displayopts::DisplayOpts; use crate::display::inputopt::InputOpt; -use crate::display::menuopts::METHOD_MENU_OPTIONS; use crate::request::command::Command; - -use crate::request::curl::{AuthKind, Curl}; -use crate::request::wget::Wget; +use crate::request::curl::AuthKind; +use crate::screens::auth::handle_authentication_screen; +use crate::screens::debug::handle_debug_screen; +use crate::screens::downloads::handle_downloads_screen; +use crate::screens::home::handle_home_screen; +use crate::screens::input::url::handle_url_input_screen; +use crate::screens::keys::handle_api_key_screen; +use crate::screens::method::handle_method_select_screen; +use crate::screens::request::handle_request_menu_screen; +use crate::screens::response::handle_response_screen; use crate::screens::screen::Screen; +use crate::screens::success::handle_success_screen; +use crate::screens::viewbody::handle_view_body_screen; + pub static CURL: &str = "curl"; pub static WGET: &str = "wget"; pub static CUSTOM: &str = "custom"; @@ -70,6 +81,7 @@ pub fn render(app: &mut App, frame: &mut Frame<'_, B>) { match &app.current_screen.clone() { // HOME SCREEN ****************************************************** Screen::Home => { + handle_home_screen(app, frame); let new_list = app.current_screen.get_list(); let area = centered_rect(70, 60, frame.size()); let mut state = ListState::with_selected(ListState::default(), Some(app.cursor)); @@ -97,6 +109,11 @@ pub fn render(app: &mut App, frame: &mut Frame<'_, B>) { // METHOD SCREEN **************************************************** Screen::Method => { + handle_method_select_screen(app, frame); + } + + Screen::Downloads => { + handle_downloads_screen(app, frame); let area = default_rect(frame.size()); let new_list = app.current_screen.get_list(); let mut state = ListState::with_selected(ListState::default(), Some(app.cursor)); @@ -164,130 +181,24 @@ pub fn render(app: &mut App, frame: &mut Frame<'_, B>) { _ => {} }; } + // KEYS SCREEN ********************************************** Screen::Keys => { - let area = default_rect(frame.size()); - let new_list = app.current_screen.get_list(); - let mut state = ListState::with_selected(ListState::default(), Some(app.cursor)); - if !app.items.is_empty() { - app.items.clear(); - } - app.items = app.current_screen.get_opts(); - app.state = Some(state.clone()); - app.state.as_mut().unwrap().select(Some(app.cursor)); - - frame.set_cursor(0, app.cursor as u16); - frame.render_stateful_widget(new_list, area, &mut state); - frame.render_widget(api_key_paragraph(), frame.size()); + handle_api_key_screen(app, frame); } // REQUEST MENU SCREEN ********************************************** Screen::RequestMenu(_) => { - let area = default_rect(frame.size()); - let new_list = app.current_screen.get_list(); - let mut state = ListState::with_selected(ListState::default(), Some(app.cursor)); - if !app.items.is_empty() { - app.items.clear(); - } - app.items = app.current_screen.get_opts(); - app.state = Some(state.clone()); - app.state.as_mut().unwrap().select(Some(app.cursor)); - frame.set_cursor(0, app.cursor as u16); - frame.render_stateful_widget(new_list, area, &mut state); - frame.render_widget(menu_paragraph(), frame.size()); - match app.selected { - // Add a URL, - Some(0) => app.goto_screen(Screen::InputMenu(InputOpt::URL)), - // Auth - Some(1) => app.goto_screen(Screen::Authentication), - // Headers - Some(2) => app.goto_screen(Screen::InputMenu(InputOpt::Headers)), - // Verbose - Some(3) => { - if app.opts.contains(&DisplayOpts::Verbose) { - app.opts.retain(|x| x != &DisplayOpts::Verbose); - app.command.as_mut().unwrap().set_verbose(false); - } else { - app.add_display_option(DisplayOpts::Verbose); - app.command.as_mut().unwrap().set_verbose(true); - } - app.selected = None; - } - // Output file, - Some(4) => { - app.goto_screen(Screen::InputMenu(InputOpt::Output)); - app.selected = None; - } - // Request Body - Some(5) => { - app.goto_screen(Screen::InputMenu(InputOpt::RequestBody)); - app.selected = None; - } - // Save this command - Some(6) => { - app.goto_screen(Screen::Commands); - app.selected = None; - } - // Execute command - Some(7) => match app.command.as_mut().unwrap().execute() { - Ok(()) => { - if let Some(response) = app.command.as_ref().unwrap().get_response() { - app.response = Some(response.clone()); - app.goto_screen(Screen::Response(response)); - } - } - Err(e) => { - app.goto_screen(Screen::Error(e.to_string())); - } - }, - _ => {} - } + handle_request_menu_screen(app, frame); } + // AUTHENTICATION SCREEN ************************************************* Screen::Authentication => { - let area = default_rect(frame.size()); - let new_list = app.current_screen.get_list(); - let mut state = ListState::with_selected(ListState::default(), Some(app.cursor)); - app.items = app.current_screen.get_opts(); - app.state = Some(state.clone()); - app.state.as_mut().unwrap().select(Some(app.cursor)); - frame.set_cursor(0, app.cursor as u16); - frame.render_stateful_widget(new_list, area, &mut state); - frame.render_widget(menu_paragraph(), frame.size()); - match app.selected { - Some(0) => app.goto_screen(Screen::InputMenu(InputOpt::Auth(AuthKind::Basic( - String::new(), - )))), - Some(1) => app.goto_screen(Screen::InputMenu(InputOpt::Auth(AuthKind::Bearer( - String::new(), - )))), - Some(2) => app.goto_screen(Screen::InputMenu(InputOpt::Auth(AuthKind::Digest( - String::new(), - )))), - Some(3) => app.goto_screen(Screen::InputMenu(InputOpt::Auth(AuthKind::AwsSigv4( - String::new(), - )))), - Some(4) => app.goto_screen(Screen::InputMenu(InputOpt::Auth(AuthKind::Spnego( - String::new(), - )))), - Some(5) => app.goto_screen(Screen::InputMenu(InputOpt::Auth(AuthKind::Kerberos( - String::new(), - )))), - Some(6) => app.goto_screen(Screen::InputMenu(InputOpt::Auth(AuthKind::Ntlm( - String::new(), - )))), - _ => {} - } + handle_authentication_screen(app, frame); } // SUCESSS SCREEN ********************************************************* Screen::Success => { - let area = default_rect(frame.size()); - app.items = app.current_screen.get_opts(); - let paragraph = Paragraph::new(Text::from(app.response.as_ref().unwrap().as_str())) - .style(Style::default().fg(Color::Yellow).bg(Color::Black)) - .alignment(Alignment::Center); - frame.set_cursor(0, app.cursor as u16); - frame.render_widget(paragraph, area); + handle_success_screen(app, frame); } // INPUT MENU SCREEN ***************************************************** @@ -297,50 +208,24 @@ pub fn render(app: &mut App, frame: &mut Frame<'_, B>) { // RESPONSE SCREEN ****************************************************** Screen::Response(resp) => { - let area = default_rect(small_alert_box(frame.size())); - let new_list = app.current_screen.get_list(); - let mut state = ListState::with_selected(ListState::default(), Some(app.cursor)); - let paragraph = Paragraph::new(Text::from(resp.as_str())) - .style(Style::default().fg(Color::Yellow).bg(Color::Black)) - .alignment(Alignment::Center); - if !app.items.is_empty() { - app.items.clear(); - } - app.items = app.current_screen.get_opts(); - app.state = Some(state.clone()); - app.state.as_mut().unwrap().select(Some(app.cursor)); - frame.set_cursor(0, app.cursor as u16); - frame.render_stateful_widget(new_list, area, &mut state); - let area_2 = small_alert_box(frame.size()); - frame.render_widget(paragraph, area_2); - match app.selected { - // write to file - Some(0) => { - app.goto_screen(Screen::InputMenu(InputOpt::Execute)); - } - // save command - Some(1) => { - app.goto_screen(Screen::Commands); - } - // view response body - Some(2) => { - app.goto_screen(Screen::ViewBody); - } - _ => {} - } + handle_response_screen(app, frame, resp.to_string()); } // VIEW BODY ******************************************************************** Screen::ViewBody => { - // screen with only the body of the response - app.items.clear(); - let area = small_rect(frame.size()); - let response = app.response.clone().unwrap(); - let paragraph = Paragraph::new(Text::from(response.as_str())) - .style(Style::default().fg(Color::Yellow).bg(Color::Black)) - .alignment(Alignment::Center); - frame.render_widget(paragraph, area); + handle_view_body_screen(app, frame); } + + // DEBUG MENU ************************************************************* + Screen::Debug => { + handle_debug_screen(app, frame); + } + + // URL INPUT SCREEN ****************************************************** + Screen::URLInput => { + handle_url_input_screen(app, frame); + } + _ => {} } } diff --git a/src/ui/widgets/boxes.rs b/src/ui/widgets/boxes.rs new file mode 100644 index 0000000..f5c0561 --- /dev/null +++ b/src/ui/widgets/boxes.rs @@ -0,0 +1,70 @@ +/* +* This file contains the functions that are used to create the different boxes +* and rectangles and such that are used in the UI + */ + +use tui::layout::{Constraint, Direction, Layout, Rect}; + +pub fn small_alert_box(r: Rect) -> Rect { + centered_rect(70, 60, r) +} + +pub fn default_rect(r: Rect) -> Rect { + centered_rect(70, 60, r) +} + +pub fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect { + let popup_layout = tui::layout::Layout::default() + .direction(tui::layout::Direction::Vertical) + .constraints( + [ + Constraint::Percentage((100 - percent_y) / 2), + Constraint::Percentage(percent_y), + Constraint::Percentage((100 - percent_y) / 2), + ] + .as_ref(), + ) + .split(r); + + tui::layout::Layout::default() + .direction(tui::layout::Direction::Horizontal) + .constraints( + [ + Constraint::Percentage((100 - percent_x) / 2), + Constraint::Percentage(percent_x), + Constraint::Percentage((100 - percent_x) / 2), + ] + .as_ref(), + ) + .split(popup_layout[1])[1] +} + +pub fn small_rect(r: Rect) -> Rect { + let layout = Layout::default() + .direction(Direction::Vertical) // Set the direction to horizontal + .constraints(vec![ + Constraint::Percentage(85), // Occupy 85% of the available space + Constraint::Percentage(15), // Occupy 15% of the available space + ]) + .split(r); + // Now, `layout` contains the two Rects based on the constraints + layout[1] +} + +// ********************************************************************************** + +pub fn single_line_input_box(frame_size: Rect) -> Rect { + let chunks = Layout::default() + .direction(Direction::Vertical) + .margin(2) + .constraints( + [ + Constraint::Length(1), + Constraint::Length(3), + Constraint::Min(1), + ] + .as_ref(), + ) + .split(frame_size); + chunks[0] +} diff --git a/src/ui/widgets/menu.rs b/src/ui/widgets/menu.rs new file mode 100644 index 0000000..67a870d --- /dev/null +++ b/src/ui/widgets/menu.rs @@ -0,0 +1,17 @@ +use tui::layout::Alignment; +use tui::style::{Color, Style}; +use tui::widgets::{Block, BorderType, Borders, Paragraph}; + +// Changed The Name Of This To Reflect What It Is. +pub fn menu_widget() -> Paragraph<'static> { + Paragraph::new("\nPress q to exit \n Press Enter to select \n Please select a Menu item\n") + .block( + Block::default() + .title("cURL-TUI") + .title_alignment(Alignment::Center) + .borders(Borders::ALL) + .border_type(BorderType::Rounded), + ) + .style(Style::default().fg(Color::Cyan).bg(Color::Black)) + .alignment(Alignment::Center) +} diff --git a/src/ui/widgets/mod.rs b/src/ui/widgets/mod.rs new file mode 100644 index 0000000..c7d7183 --- /dev/null +++ b/src/ui/widgets/mod.rs @@ -0,0 +1,5 @@ +// Widgets Related To Boxes And Rectangles +pub mod boxes; + +// Widgets Related To Menus +pub mod menu;