diff --git a/.gitignore b/.gitignore index 55d0c0e..8e67e72 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,6 @@ target/ **/*.rs.bk .DS_Store .idea -.env \ No newline at end of file +.env +.vscode +ignore \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index c2bfd5a..d44b60a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "aho-corasick" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +dependencies = [ + "memchr", +] + [[package]] name = "android_system_properties" version = "0.1.4" @@ -35,6 +44,55 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6342bd4f5a1205d7f41e94a41a901f5647c938cdfa96036338e8533c9d6c2450" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + +[[package]] +name = "anstyle-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +dependencies = [ + "anstyle", + "windows-sys 0.48.0", +] + [[package]] name = "arrayvec" version = "0.7.2" @@ -43,10 +101,11 @@ checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" [[package]] name = "assert_cmd" -version = "2.0.8" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9834fcc22e0874394a010230586367d4a3e9f11b560f469262678547e1d2575e" +checksum = "86d6b683edf8d1119fe420a94f8a7e389239666aa72e65495d91c00462510151" dependencies = [ + "anstyle", "bstr", "doc-comment", "predicates", @@ -173,9 +232,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.23" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" dependencies = [ "iana-time-zone", "js-sys", @@ -215,39 +274,47 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.8" +version = "4.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" +checksum = "956ac1f6381d8d82ab4684768f89c0ea3afe66925ceadb4eeb3fc452ffc55d62" dependencies = [ - "bitflags", + "clap_builder", "clap_derive", - "clap_lex 0.3.0", - "is-terminal", "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84080e799e54cff944f4b4a4b0e71630b0e0443b25b985175c7dddc1a859b749" +dependencies = [ + "anstream", + "anstyle", + "bitflags", + "clap_lex 0.4.1", "strsim", - "termcolor", ] [[package]] name = "clap_complete" -version = "4.1.4" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501ff0a401473ea1d4c3b125ff95506b62c5bc5768d818634195fbb7c4ad5ff4" +checksum = "1a19591b2ab0e3c04b588a0e04ddde7b9eaa423646d1b4a8092879216bf47473" dependencies = [ - "clap 4.1.8", + "clap 4.2.4", ] [[package]] name = "clap_derive" -version = "4.1.8" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0" +checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.15", ] [[package]] @@ -261,12 +328,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" -dependencies = [ - "os_str_bytes", -] +checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" [[package]] name = "clipboard" @@ -303,6 +367,12 @@ dependencies = [ "owo-colors", ] +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "confy" version = "0.5.1" @@ -317,9 +387,9 @@ dependencies = [ [[package]] name = "conpty" -version = "0.3.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "977baae4026273d7f9bb69a0a8eb4aed7ab9dac98799f742dce09173a9734754" +checksum = "b72b06487a0d4683349ad74d62e87ad639b09667082b3c495c5b6bab7d84b3da" dependencies = [ "windows", ] @@ -397,7 +467,7 @@ dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset", + "memoffset 0.6.5", "once_cell", "scopeguard", ] @@ -443,7 +513,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn", + "syn 1.0.105", ] [[package]] @@ -454,7 +524,7 @@ checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" dependencies = [ "darling_core", "quote", - "syn", + "syn 1.0.105", ] [[package]] @@ -485,7 +555,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn", + "syn 1.0.105", ] [[package]] @@ -495,18 +565,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68" dependencies = [ "derive_builder_core", - "syn", + "syn 1.0.105", ] [[package]] name = "dialoguer" -version = "0.10.3" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af3c796f3b0b408d9fd581611b47fa850821fcb84aa640b83a3c1a5be2d691f2" +checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" dependencies = [ "console", + "fuzzy-matcher", "shell-words", "tempfile", + "thiserror", "zeroize", ] @@ -600,13 +672,13 @@ dependencies = [ [[package]] name = "errno" -version = "0.2.8" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -621,12 +693,12 @@ dependencies = [ [[package]] name = "expectrl" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ae3a1de9c4a0cfc3badf6f98bf0736fe3f05e3b6da5b8f5288a4726fcc6f746" +checksum = "b36f34b0325008d05b0e9be8361bfa8a0fb905f10de0d951c2621c59e811cb91" dependencies = [ "conpty", - "nix 0.25.1", + "nix 0.26.2", "ptyprocess", "regex", ] @@ -746,7 +818,7 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ - "aho-corasick", + "aho-corasick 0.7.18", "bstr", "fnv", "log", @@ -778,9 +850,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -793,12 +865,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" [[package]] name = "hex" @@ -886,19 +955,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] name = "is-terminal" -version = "0.4.1" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi 0.3.1", "io-lifetimes", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -954,9 +1023,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "36eb31c1778188ae1e64398743890d0877fef36d11521ac60406b42016e8c2cf" [[package]] name = "lock_api" @@ -1007,6 +1076,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + [[package]] name = "miniz_oxide" version = "0.5.3" @@ -1018,40 +1096,41 @@ dependencies = [ [[package]] name = "nix" -version = "0.21.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c3728fec49d363a50a8828a190b379a446cc5cf085c06259bbbeb34447e4ec7" +checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" dependencies = [ "bitflags", - "cc", "cfg-if", "libc", - "memoffset", ] [[package]] name = "nix" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" dependencies = [ + "autocfg", "bitflags", "cfg-if", "libc", + "memoffset 0.6.5", + "pin-utils", ] [[package]] name = "nix" -version = "0.25.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "autocfg", "bitflags", "cfg-if", "libc", - "memoffset", + "memoffset 0.7.1", "pin-utils", + "static_assertions", ] [[package]] @@ -1180,7 +1259,7 @@ dependencies = [ "cfg-if", "instant", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "winapi", ] @@ -1219,10 +1298,11 @@ checksum = "81bdd679d533107e090c2704a35982fc06302e30898e63ffa26a81155c012e92" [[package]] name = "predicates" -version = "2.1.5" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +checksum = "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9" dependencies = [ + "anstyle", "difflib", "float-cmp", "itertools", @@ -1233,9 +1313,9 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.3" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da1c2388b1513e1b605fcec39a95e0a9e8ef088f71443ef37099fa9ae6673fcb" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" [[package]] name = "predicates-tree" @@ -1247,53 +1327,29 @@ dependencies = [ "termtree", ] -[[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" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] [[package]] name = "ptyprocess" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69c28fcebfd842bfe19d69409fc321230ea8c1bebe31f274906485c761ce1917" +checksum = "7e05aef7befb11a210468a2d77d978dde2c6381a0381e33beb575e91f57fe8cf" dependencies = [ - "nix 0.21.0", + "nix 0.26.2", ] [[package]] name = "quote" -version = "1.0.21" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] @@ -1331,6 +1387,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.4.3" @@ -1338,19 +1403,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", - "redox_syscall", + "redox_syscall 0.2.16", "thiserror", ] [[package]] name = "regex" -version = "1.7.1" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" dependencies = [ - "aho-corasick", + "aho-corasick 1.0.1", "memchr", - "regex-syntax", + "regex-syntax 0.7.1", ] [[package]] @@ -1365,6 +1430,12 @@ version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +[[package]] +name = "regex-syntax" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" + [[package]] name = "ring" version = "0.16.20" @@ -1388,16 +1459,16 @@ checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustix" -version = "0.36.5" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588" +checksum = "62b24138615de35e32031d041a09032ef3487a616d901ca4db224e7d557efae2" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1463,26 +1534,26 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.154" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cdd151213925e7f1ab45a9bbfb129316bd00799784b174b7cc7bcd16961c49e" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" [[package]] name = "serde_derive" -version = "1.0.154" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fc80d722935453bcafdc2c9a73cd6fac4dc1938f0346035d84bf99fa9e33217" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.15", ] [[package]] name = "serde_json" -version = "1.0.94" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "itoa", "ryu", @@ -1491,9 +1562,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.19" +version = "0.9.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82e6c8c047aa50a7328632d067bcae6ef38772a79e28daf32f735e0e4f3dd10" +checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c" dependencies = [ "indexmap", "itoa", @@ -1571,6 +1642,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.10.0" @@ -1579,21 +1656,21 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.24.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" [[package]] name = "strum_macros" -version = "0.24.3" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ "heck", "proc-macro2", "quote", "rustversion", - "syn", + "syn 2.0.15", ] [[package]] @@ -1607,6 +1684,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syntect" version = "5.0.0" @@ -1621,7 +1709,7 @@ dependencies = [ "lazy_static", "once_cell", "plist", - "regex-syntax", + "regex-syntax 0.6.27", "serde", "serde_derive", "serde_json", @@ -1632,15 +1720,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.3.5", "rustix", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1687,13 +1775,13 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "the-way" -version = "0.19.1" +version = "0.19.2" dependencies = [ "assert_cmd", "bincode", "chrono", "chrono-english", - "clap 4.1.8", + "clap 4.2.4", "clap_complete", "clipboard", "color-eyre", @@ -1724,22 +1812,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.15", ] [[package]] @@ -1891,15 +1979,9 @@ dependencies = [ [[package]] name = "utf8parse" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" - -[[package]] -name = "version_check" -version = "0.9.4" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "vte" @@ -1975,7 +2057,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.105", "wasm-bindgen-shared", ] @@ -1997,7 +2079,7 @@ checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.105", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2070,15 +2152,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.29.0" +version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac7fef12f4b59cd0a29339406cc9203ab44e440ddff6b3f5a41455349fa9cf3" +checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" dependencies = [ - "windows_aarch64_msvc 0.29.0", - "windows_i686_gnu 0.29.0", - "windows_i686_msvc 0.29.0", - "windows_x86_64_gnu 0.29.0", - "windows_x86_64_msvc 0.29.0", + "windows-targets 0.42.2", ] [[package]] @@ -2087,86 +2165,146 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", - "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", - "windows_x86_64_msvc 0.42.0", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" -version = "0.29.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d027175d00b01e0cbeb97d6ab6ebe03b12330a35786cbaca5252b1c4bf5d9b" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] name = "windows_i686_gnu" -version = "0.29.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8793f59f7b8e8b01eda1a652b2697d87b93097198ae85f823b969ca5b89bba58" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" -version = "0.29.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8602f6c418b67024be2996c512f5f995de3ba417f4c75af68401ab8756796ae4" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] name = "windows_x86_64_gnu" -version = "0.29.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d615f419543e0bd7d2b3323af0d86ff19cbc4f816e6453f36a2c2ce889c354" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] name = "windows_x86_64_msvc" -version = "0.29.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d95421d9ed3672c280884da53201a5c46b7b2765ca6faf34b0d71cf34a3561" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "x11-clipboard" diff --git a/Cargo.toml b/Cargo.toml index 46f8de9..cd3815c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,8 @@ exclude = [ [dependencies] # Argument parsing -clap = { version = "4.1.8", features = ["derive"] } -clap_complete = "4.1.4" +clap = { version = "4.2.4", features = ["derive"] } +clap_complete = "4.2.1" # Configuration management confy = "0.5.1" @@ -27,24 +27,24 @@ directories-next = "1.0.2" # Error management eyre = "0.6.8" color-eyre = { version = "0.6.2", default-features = false } -thiserror = "1.0.39" +thiserror = "1.0.40" # Database related sled = "0.34.7" bincode = "1.3.3" # Serializing -serde = "1.0.154" -serde_json = "1.0.94" -serde_derive = "1.0.154" -serde_yaml = "0.9.19" +serde = "1.0.160" +serde_json = "1.0.96" +serde_derive = "1.0.160" +serde_yaml = "0.9.21" # Parsing and manipulating dates -chrono = { version = "0.4.23", features = ["serde"] } +chrono = { version = "0.4.24", features = ["serde"] } chrono-english = "0.1.7" # Taking user input and showing progress -dialoguer = "0.10.3" +dialoguer = {version = "0.11.0", features = ["completion", "history", "fuzzy-select"]} indicatif = "0.17.3" # Fuzzy search @@ -58,17 +58,17 @@ termcolor = "1.2.0" # Sync to Gist/GitLab ureq = { version = "2.6.2", features = ["json"] } -strum = "0.24.1" -strum_macros = "0.24.3" +strum = "0.25.0" +strum_macros = "0.25.3" # pattern filter and filling shell script variables -regex = "1.7.1" +regex = "1.8.1" [dev-dependencies] -assert_cmd = "2.0.8" -predicates = "2.1.5" -tempfile = "3.4.0" -expectrl = "0.6.0" +assert_cmd = "2.0.11" +predicates = "3.0.3" +tempfile = "3.5.0" +expectrl = "0.7.0" [target.'cfg(target_os = "macos")'.dev-dependencies] clipboard = "0.5.0" diff --git a/src/the_way/cli.rs b/src/the_way/cli.rs index 0412174..be62a10 100644 --- a/src/the_way/cli.rs +++ b/src/the_way/cli.rs @@ -142,6 +142,16 @@ pub enum TheWaySubcommand { /// Index of snippet to show index: usize, }, + /// Lists (optionally filtered) tags + Tags { + #[clap(flatten)] + filters: Filters, + }, + /// Lists (optionally filtered) languages + Languages { + #[clap(flatten)] + filters: Filters, + }, } #[derive(Parser, Debug)] diff --git a/src/the_way/database.rs b/src/the_way/database.rs index d09959e..34fafa2 100644 --- a/src/the_way/database.rs +++ b/src/the_way/database.rs @@ -118,6 +118,38 @@ impl TheWay { .collect::>>() } + /// List all tags + pub(crate) fn list_tags(&self) -> color_eyre::Result> { + self.tag_tree()? + .iter() + .map(|item| { + item.map_err(|_e| { + LostTheWay::OutOfCheeseError { + message: "sled PageCache Error".into(), + } + .into() + }) + .and_then(|(tag, _)| String::from_utf8(tag.to_vec()).map_err(|e| e.into())) + }) + .collect::>>() + } + + /// List all tags + pub(crate) fn list_languages(&self) -> color_eyre::Result> { + self.language_tree()? + .iter() + .map(|item| { + item.map_err(|_e| { + LostTheWay::OutOfCheeseError { + message: "sled PageCache Error".into(), + } + .into() + }) + .and_then(|(tag, _)| String::from_utf8(tag.to_vec()).map_err(|e| e.into())) + }) + .collect::>>() + } + // TODO: think about how deletions should affect snippet indices pub(crate) fn increment_snippet_index(&mut self) -> color_eyre::Result<()> { self.db.insert( diff --git a/src/the_way/mod.rs b/src/the_way/mod.rs index 435ec7f..98db484 100644 --- a/src/the_way/mod.rs +++ b/src/the_way/mod.rs @@ -46,6 +46,12 @@ pub struct TheWay { plain: bool, } +pub enum ListType { + Snippet, + Tag, + Language, +} + // All command-line related functions impl TheWay { /// Initialize program with command line input. @@ -89,7 +95,7 @@ impl TheWay { TheWaySubcommand::Edit { index } => self.edit(index), TheWaySubcommand::Del { index, force } => self.delete(index, force), TheWaySubcommand::View { index } => self.view(index), - TheWaySubcommand::List { filters } => self.list(&filters), + TheWaySubcommand::List { filters } => self.list(&filters, ListType::Snippet), TheWaySubcommand::Import { file, gist_url, @@ -107,13 +113,20 @@ impl TheWay { ConfigCommand::Get => TheWayConfig::print_config_location(), }, TheWaySubcommand::Sync { cmd, force } => self.sync(cmd, force), + TheWaySubcommand::Tags { filters } => self.list(&filters, ListType::Tag), + TheWaySubcommand::Languages { filters } => self.list(&filters, ListType::Language), } } /// Adds a new snippet fn the_way(&mut self) -> color_eyre::Result<()> { - let snippet = - Snippet::from_user(self.get_current_snippet_index()? + 1, &self.languages, None)?; + let snippet = Snippet::from_user( + self.get_current_snippet_index()? + 1, + &self.languages, + self.list_tags()?, + self.list_languages()?, + None, + )?; let index = self.add_snippet(&snippet)?; self.color_print(&format!("Snippet #{index} added\n"))?; self.increment_snippet_index()?; @@ -122,8 +135,11 @@ impl TheWay { /// Adds a new shell snippet fn the_way_cmd(&mut self, code: Option) -> color_eyre::Result<()> { - let snippet = - Snippet::cmd_from_user(self.get_current_snippet_index()? + 1, code.as_deref())?; + let snippet = Snippet::cmd_from_user( + self.get_current_snippet_index()? + 1, + code.as_deref(), + self.list_tags()?, + )?; let index = self.add_snippet(&snippet)?; self.color_print(&format!("Snippet #{index} added\n"))?; self.increment_snippet_index()?; @@ -150,7 +166,13 @@ impl TheWay { /// Modify a stored snippet's information fn edit(&mut self, index: usize) -> color_eyre::Result<()> { let old_snippet = self.get_snippet(index)?; - let new_snippet = Snippet::from_user(index, &self.languages, Some(&old_snippet))?; + let new_snippet = Snippet::from_user( + index, + &self.languages, + self.list_tags()?, + self.list_languages()?, + Some(&old_snippet), + )?; self.delete_snippet(index)?; self.add_snippet(&new_snippet)?; self.color_print(&format!("Snippet #{index} changed\n"))?; @@ -282,11 +304,55 @@ impl TheWay { Ok(()) } + fn show_counts( + &self, + object_to_count: HashMap, + list_type: ListType, + ) -> color_eyre::Result<()> { + let mut objects = object_to_count.iter().collect::>(); + objects.sort_by(|(_, a), (_, b)| b.cmp(a)); + let mut colorized = Vec::new(); + for (object, count) in objects { + match list_type { + ListType::Tag => { + colorized.push((self.highlighter.tag_style, object.to_string())); + } + ListType::Language => { + colorized.push((self.highlighter.accent_style, object.to_string())); + } + _ => unreachable!(), + } + colorized.push((self.highlighter.main_style, format!(" ({count})\n"))); + } + utils::smart_print(&colorized, false, self.colorize, self.plain)?; + Ok(()) + } + /// Lists snippets (optionally filtered) - fn list(&self, filters: &Filters) -> color_eyre::Result<()> { + fn list(&self, filters: &Filters, list_type: ListType) -> color_eyre::Result<()> { let mut snippets = self.filter_snippets(filters)?; - snippets.sort_by(|a, b| a.index.cmp(&b.index)); - self.show_snippets(&snippets)?; + match list_type { + ListType::Snippet => { + snippets.sort_by(|a, b| a.index.cmp(&b.index)); + self.show_snippets(&snippets)?; + } + ListType::Tag => { + let mut tags = HashMap::new(); + for snippet in &snippets { + for tag in &snippet.tags { + *tags.entry(tag.to_owned()).or_insert(0) += 1; + } + } + self.show_counts(tags, list_type)?; + } + ListType::Language => { + let mut languages = HashMap::new(); + for snippet in &snippets { + *languages.entry(snippet.language.to_owned()).or_insert(0) += 1; + } + self.show_counts(languages, list_type)?; + } + } Ok(()) } diff --git a/src/the_way/snippet.rs b/src/the_way/snippet.rs index ed4e9b3..5f5fdf4 100644 --- a/src/the_way/snippet.rs +++ b/src/the_way/snippet.rs @@ -93,6 +93,8 @@ impl Snippet { pub(crate) fn from_user( index: usize, languages: &HashMap, + used_tags: Vec, + used_languages: Vec, old_snippet: Option<&Self>, ) -> color_eyre::Result { let (old_description, old_language, old_tags, old_date, old_code) = match old_snippet { @@ -105,18 +107,41 @@ impl Snippet { ), None => (None, None, None, None, None), }; + let description = utils::user_input( + "Description", + old_description, + true, + false, + utils::TheWayCompletion::Empty, + )?; + let mut all_languages = used_languages; + let mut unused_languages = languages + .keys() + .map(|s| s.to_ascii_lowercase()) + .collect::>(); + unused_languages.sort(); + all_languages.extend(unused_languages); - let description = utils::user_input("Description", old_description, true, false)?; + let language_completions = utils::TheWayCompletion::Language(all_languages); let language = - utils::user_input("Language", old_language, true, false)?.to_ascii_lowercase(); + utils::user_input("Language", old_language, true, false, language_completions)? + .to_ascii_lowercase(); let extension = Language::get_extension(&language, languages); - let tags = utils::user_input("Tags (space separated)", old_tags.as_deref(), true, true)?; + let tag_completions = utils::TheWayCompletion::Tag(used_tags); + let tags = utils::user_input( + "Tags (space separated)", + old_tags.as_deref(), + true, + true, + tag_completions, + )?; let date = match old_date { Some(_) => utils::parse_date(&utils::user_input( "Date", old_date.as_deref(), true, false, + utils::TheWayCompletion::Empty, )?)?, None => Utc::now(), }; @@ -130,9 +155,10 @@ impl Snippet { } else { let mut input = utils::user_input( "Code snippet (leave empty to open external editor)", - None, // default - false, // show default - true, // allow empty + None, // default + false, // show default + true, // allow empty, + utils::TheWayCompletion::Empty, // completions )?; if input.is_empty() { input = utils::external_editor_input(None, &extension)?; @@ -152,10 +178,26 @@ impl Snippet { } /// Queries user for new shell snippet info - pub(crate) fn cmd_from_user(index: usize, code: Option<&str>) -> color_eyre::Result { - let code = utils::user_input("Command", code, true, false)?; - let description = utils::user_input("Description", None, true, false)?; - let tags = utils::user_input("Tags (space separated)", None, true, true)?; + pub(crate) fn cmd_from_user( + index: usize, + code: Option<&str>, + all_tags: Vec, + ) -> color_eyre::Result { + let code = utils::user_input("Command", code, true, false, utils::TheWayCompletion::Empty)?; + let description = utils::user_input( + "Description", + None, + true, + false, + utils::TheWayCompletion::Empty, + )?; + let tags = utils::user_input( + "Tags (space separated)", + None, + true, + true, + utils::TheWayCompletion::Tag(all_tags), + )?; Ok(Self::new( index, description, @@ -283,7 +325,13 @@ impl Snippet { if let std::collections::hash_map::Entry::Vacant(e) = filled_parameters.entry(parameter_name.clone()) { - let filled = utils::user_input(¶meter_name, default, true, false)?; + let filled = utils::user_input( + ¶meter_name, + default, + true, + false, + utils::TheWayCompletion::Empty, + )?; e.insert(filled); } } diff --git a/src/utils.rs b/src/utils.rs index 9ffcbcc..3425d6d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,3 +1,4 @@ +use std::collections::HashSet; use std::io::Write; use std::process::{Command, Stdio}; use std::str; @@ -5,7 +6,7 @@ use std::str; use chrono::{DateTime, NaiveDateTime, Utc}; use chrono_english::{parse_date_string, Dialect}; use color_eyre::Help; -use dialoguer::{Confirm, Editor, Input}; +use dialoguer::{Completion, Confirm, Editor, Input}; use syntect::highlighting::Style; use syntect::util::as_24_bit_terminal_escaped; @@ -164,23 +165,25 @@ pub fn user_input( default: Option<&str>, show_default: bool, allow_empty: bool, + completions: TheWayCompletion, ) -> color_eyre::Result { let theme = dialoguer::theme::ColorfulTheme::default(); match default { Some(default) => { - let mut input = Input::with_theme(&theme); - input + let mut input = Input::with_theme(&theme) .with_prompt(message) + .completion_with(&completions) .allow_empty(allow_empty) .default(default.to_owned()) .show_default(false); if show_default { - input.with_initial_text(default); + input = input.with_initial_text(default); } Ok(input.interact_text()?.trim().to_owned()) } None => Ok(Input::::with_theme(&theme) .with_prompt(message) + .completion_with(&completions) .allow_empty(allow_empty) .interact_text()? .trim() @@ -256,3 +259,54 @@ pub fn smart_print( )?; Ok(()) } + +#[derive(Debug)] +pub enum TheWayCompletion { + Language(Vec), + Tag(Vec), + Empty, +} + +impl Completion for TheWayCompletion { + fn get(&self, input: &str) -> Option { + match self { + Self::Language(languages) => { + let matches = languages + .iter() + .filter(|option| option.starts_with(input)) + .collect::>(); + + if !matches.is_empty() { + Some(matches[0].to_string()) + } else { + None + } + } + Self::Tag(tags) => { + let current_tags_list = input + .split(' ') + .map(|s| s.to_string()) + .collect::>(); + let last_input = input.split(' ').last().unwrap_or(""); + let last_space = input.rfind(' ').unwrap_or(0); + let matches = tags + .iter() + .filter(|option| { + option.starts_with(last_input) && !current_tags_list.contains(*option) + }) + .collect::>(); + + if !matches.is_empty() { + Some( + (input[..last_space].trim().to_string() + " " + matches[0]) + .trim() + .to_string(), + ) + } else { + None + } + } + Self::Empty => None, + } + } +}