From 088dda196e9beebb6e8953ebfbebde887fb3bc93 Mon Sep 17 00:00:00 2001 From: Nitestack <74626967+Nitestack@users.noreply.github.com> Date: Sat, 23 Mar 2024 02:29:18 +0100 Subject: [PATCH] update: alpha release --- Cargo.lock | 837 ++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 14 +- LICENSE | 201 +++++++++++ README.md | 1 + src/cli.rs | 41 +++ src/cmds/add.rs | 92 +++++ src/cmds/list.rs | 32 ++ src/cmds/mod.rs | 4 + src/cmds/remove.rs | 94 +++++ src/cmds/select.rs | 72 ++++ src/main.rs | 16 +- src/store.rs | 86 +++++ src/utils/logger.rs | 48 +++ src/utils/mod.rs | 81 +++++ 14 files changed, 1617 insertions(+), 2 deletions(-) create mode 100644 Cargo.lock create mode 100644 LICENSE create mode 100644 README.md create mode 100644 src/cli.rs create mode 100644 src/cmds/add.rs create mode 100644 src/cmds/list.rs create mode 100644 src/cmds/mod.rs create mode 100644 src/cmds/remove.rs create mode 100644 src/cmds/select.rs create mode 100644 src/store.rs create mode 100644 src/utils/logger.rs create mode 100644 src/utils/mod.rs diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..74201ca --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,837 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "cliclack" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be29210ca32b96e4f67fe9a520d2eeacc078d94ff4027100dc6b7262fdfec5c4" +dependencies = [ + "console", + "indicatif", + "once_cell", + "textwrap", + "zeroize", +] + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "colored" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys 0.48.0", +] + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode 0.3.6", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.52.0", +] + +[[package]] +name = "csv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "indicatif" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.2", + "libc", + "redox_syscall", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "merge" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9" +dependencies = [ + "merge_derive", + "num-traits", +] + +[[package]] +name = "merge_derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "nvim-switcher" +version = "0.1.0" +dependencies = [ + "clap", + "cliclack", + "colored", + "console", + "dirs", + "merge", + "prettytable-rs", + "regex", + "serde", + "serde_json", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + +[[package]] +name = "prettytable-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a" +dependencies = [ + "csv", + "encode_unicode 1.0.0", + "is-terminal", + "lazy_static", + "term", + "unicode-width", +] + +[[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 1.0.109", + "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.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "serde_json" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-targets" +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", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] diff --git a/Cargo.toml b/Cargo.toml index 976dd83..b042824 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,13 +2,25 @@ name = "nvim-switcher" version = "0.1.0" edition = "2021" -description = "A CLI tool to switch between different Neovim configurations." +description = "A CLI to easily switch between multiple Neovim configuration environments" readme = "README.md" keywords = ["neovim", "nvim", "switcher", "cli"] +categories = ["command-line-utilities"] +repository = "https://github.com/Nitestack/nvim-switcher" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +clap = { version = "4.5.3", features = ["derive"] } +cliclack = "0.1.13" +colored = "2.1.0" +console = "0.15.8" +dirs = "5.0.1" +merge = "0.1.0" +prettytable-rs = "0.10.0" +regex = "1.10.3" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" [[bin]] name = "nvims" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2375b71 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Neovim Configuration Switcher diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..37ab866 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,41 @@ +use crate::{ + cmds::*, + utils::{is_neovim_installed, print_outro_cancel}, +}; +use clap::{Parser, Subcommand}; + +#[derive(Parser, Debug)] +#[command(name = "nvims", author = "Nitestack", version, about, long_about = None)] +struct Cli { + #[command(subcommand)] + command: Option, +} + +#[derive(Subcommand, Debug)] +enum Commands { + /// Add a new Neovim configuration + Add {}, + /// Remove a Neovim configuration + Remove {}, + /// Configure a Neovim configuration + Config {}, + /// List all Neovim configurations + List {}, +} + +pub fn run_cli() { + let cli = Cli::parse(); + + if !is_neovim_installed() { + print_outro_cancel("Neovim not installed! Please install Neovim and try again."); + return; + } + + match &cli.command { + Some(Commands::Add {}) => add::add_config(), + Some(Commands::Remove {}) => remove::remove_config(), + Some(Commands::Config {}) => {} + Some(Commands::List {}) => list::list_configs(), + None => select::select_config(), + } +} diff --git a/src/cmds/add.rs b/src/cmds/add.rs new file mode 100644 index 0000000..b936031 --- /dev/null +++ b/src/cmds/add.rs @@ -0,0 +1,92 @@ +use cliclack::{input, spinner}; +use std::process::Command; + +use crate::store::{get_config, set_config, Config, NeovimConfig}; +use crate::utils::{get_nvim_config_dir, is_valid_github_url, print_intro, print_outro}; + +pub fn add_config() { + let configs_dir = get_nvim_config_dir(None); + + print_intro(None); + + let name: String = input("Name") + .placeholder("Configuration Name") + .validate(|input: &String| { + if get_config() + .configs + .iter() + .any(|nvim_config| nvim_config.name.to_lowercase() == *input.to_lowercase()) + { + Err("Configuration name already exists") + } else { + Ok(()) + } + }) + .interact() + .unwrap(); + let repo_url: String = input("GitHub Repository URL") + .placeholder("https://github.com/user/repo") + .validate(|input: &String| { + if !is_valid_github_url(input) { + Err("URL must be a valid GitHub repository URL") + } else { + Ok(()) + } + }) + .interact() + .unwrap(); + let nvim_dir_name: String = input(format!( + "{} ({})", + "Neovim Directory Name", + configs_dir.join("").to_str().unwrap() + )) + .placeholder("configuration-name") + .validate(|input: &String| { + if get_config() + .configs + .iter() + .any(|nvim_config| nvim_config.nvim_dir_name == *input) + { + Err("Directory name already exists") + } else { + Ok(()) + } + }) + .interact() + .unwrap(); + + let mut spinner = spinner(); + spinner.start(format!("Cloning {} from '{}'...", name, repo_url).as_str()); + Command::new("git") + .arg("clone") + .arg(&repo_url) + .arg(configs_dir.join(&nvim_dir_name)) + .arg("--depth") + .arg("1") + .output() + .expect("Failed to clone repository"); + spinner.stop(format!("Cloned {} from '{}'", name, repo_url).as_str()); + + spinner.start("Editing user config..."); + set_config( + Config { + configs: vec![NeovimConfig { + name: name.clone(), + repo_url: repo_url.clone(), + nvim_dir_name: nvim_dir_name.clone(), + }], + }, + false, + ); + spinner.stop("User config saved"); + + print_outro(Some( + format!( + "Added {} ({}) to '{}'", + name, + repo_url, + configs_dir.join(nvim_dir_name).to_str().unwrap() + ) + .as_str(), + )); +} diff --git a/src/cmds/list.rs b/src/cmds/list.rs new file mode 100644 index 0000000..5ee9535 --- /dev/null +++ b/src/cmds/list.rs @@ -0,0 +1,32 @@ +use prettytable::{color, Attr, Cell, Row, Table}; + +use crate::{store::get_config, utils::get_nvim_config_dir}; + +pub fn list_configs() { + let config = get_config(); + let config_dir = get_nvim_config_dir(None); + let mut table = Table::new(); + + table.add_row(Row::new(vec![ + Cell::new("Name") + .with_style(Attr::Bold) + .with_style(Attr::ForegroundColor(color::GREEN)), + Cell::new("Config Directory"), + Cell::new("GitHub URL"), + ])); + + for nvim_config in config.configs.iter() { + table.add_row(Row::new(vec![ + Cell::new(&nvim_config.name), + Cell::new( + config_dir + .join(&nvim_config.nvim_dir_name) + .to_str() + .unwrap(), + ), + Cell::new(&nvim_config.repo_url), + ])); + } + + table.printstd(); +} diff --git a/src/cmds/mod.rs b/src/cmds/mod.rs new file mode 100644 index 0000000..9250958 --- /dev/null +++ b/src/cmds/mod.rs @@ -0,0 +1,4 @@ +pub mod add; +pub mod list; +pub mod remove; +pub mod select; diff --git a/src/cmds/remove.rs b/src/cmds/remove.rs new file mode 100644 index 0000000..5adea91 --- /dev/null +++ b/src/cmds/remove.rs @@ -0,0 +1,94 @@ +use cliclack::{select, spinner}; + +use crate::{ + store::{get_config, set_config}, + utils::{get_nvim_config_dir, print_empty_configurations, print_intro, print_outro}, +}; + +use std::{env, fs, ops::Add}; + +pub fn remove_config() { + if print_empty_configurations() { + return; + } + print_intro(None); + + let config = get_config(); + + let selected_key = select("Select Neovim Distribution") + .items( + &config + .configs + .iter() + .map(|s| (s.nvim_dir_name.clone(), s.name.clone(), "")) + .collect::>(), + ) + .interact() + .unwrap(); + + let selected_item = &config + .configs + .iter() + .find(|s| s.nvim_dir_name == selected_key) + .expect("Failed to find selected item"); + + let mut spinner = spinner(); + spinner.start( + format!( + "Removing config, data, cache and state for {}...", + selected_item.name + ) + .as_str(), + ); + let dir_name = if env::consts::OS == "windows" { + selected_item.nvim_dir_name.to_string().add("-data") + } else { + selected_item.nvim_dir_name.clone() + }; + + fs::remove_dir_all(get_nvim_config_dir(Some(&selected_item.nvim_dir_name))).ok(); + fs::remove_dir_all( + dirs::data_local_dir() + .expect("Failed to get data directory") + .join(&dir_name), + ) + .ok(); + fs::remove_dir_all({ + let cache_dir = dirs::cache_dir().expect("Failed to get cache directory"); + if env::consts::OS == "windows" { + dirs::data_local_dir() + .expect("Failed to get temp directory") + .join("Temp") + .join(&dir_name) + } else { + cache_dir.join(&dir_name) + } + }) + .ok(); + + //TODO: As long as `state_dir` returns nothing on Windows, this should work. + if let Some(state_dir) = dirs::state_dir() { + fs::remove_dir_all(state_dir.join(&selected_item.nvim_dir_name)).ok(); + } + spinner.stop("Removed config, data, cache and state"); + + spinner.start("Editing user config..."); + let mut new_config = config.clone(); + new_config.configs.swap_remove( + config + .configs + .iter() + .position(|s| s.nvim_dir_name == selected_item.nvim_dir_name) + .expect("Failed to find selected item"), + ); + set_config(new_config, true); + spinner.stop("User config saved"); + + print_outro(Some( + format!( + "Removed {} ({})", + &selected_item.name, &selected_item.repo_url, + ) + .as_str(), + )); +} diff --git a/src/cmds/select.rs b/src/cmds/select.rs new file mode 100644 index 0000000..c835484 --- /dev/null +++ b/src/cmds/select.rs @@ -0,0 +1,72 @@ +// use cliclack::select; + +use crate::{ + store::get_config, + utils::{ + is_fzf_installed, print_empty_configurations, print_intro, print_outro, print_outro_cancel, + }, +}; + +use std::{ + io::{Read, Write}, + process::{Command, Stdio}, +}; + +pub fn select_config() { + if !is_fzf_installed() { + print_intro(None); + print_outro_cancel("fzf not installed! Please install fzf and try again."); + return; + } + + if print_empty_configurations() { + return; + } + + let config = get_config(); + + let items = config + .configs + .iter() + .map(|s| s.name.clone()) + .collect::>() + .join("\n"); + + let mut child = Command::new("fzf") + .arg("--prompt= Select Neovim Distribution  ") + .arg("--height=~50%") + .arg("--layout=reverse") + .arg("--border") + .arg("--exit-0") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .expect("Failed to spawn fzf process"); + + if let Some(mut stdin) = child.stdin.take() { + stdin.write_all(items.as_bytes()).unwrap(); + } + + let mut output = String::new(); + if let Some(mut stdout) = child.stdout.take() { + stdout.read_to_string(&mut output).unwrap(); + } + + Command::new("nvim") + .env( + "NVIM_APPNAME", + config + .configs + .iter() + .find(|s| s.name == output.trim()) + .expect("Failed to find selected item") + .nvim_dir_name + .clone(), + ) + .spawn() + .unwrap() + .wait() + .ok(); + + print_outro(None); +} diff --git a/src/main.rs b/src/main.rs index e7a11a9..f2aaf1b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,17 @@ +mod cli; +mod cmds; +mod store; +mod utils; + +extern crate core; + +use crate::{ + cli::run_cli, + utils::{disable_emojis, enable_emojis}, +}; + fn main() { - println!("Hello, world!"); + enable_emojis(); + run_cli(); + disable_emojis(); } diff --git a/src/store.rs b/src/store.rs new file mode 100644 index 0000000..b6ef6fa --- /dev/null +++ b/src/store.rs @@ -0,0 +1,86 @@ +use merge::Merge; +use serde::{Deserialize, Serialize}; +use std::fs; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +#[derive(Serialize, Deserialize, Debug, Clone, Merge)] +pub struct Config { + #[merge(strategy = merge::vec::append)] + pub configs: Vec, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct NeovimConfig { + pub name: String, + pub repo_url: String, + pub nvim_dir_name: String, +} + +fn get_default_config() -> Config { + Config { configs: vec![] } +} + +fn get_config_dir() -> PathBuf { + match dirs::config_dir() { + Some(dir) => dir.join("nvims"), + None => panic!("Could not get config dir"), + } +} + +fn get_config_path() -> String { + match get_config_dir().join("config.json").to_str() { + Some(path) => path.to_string(), + None => panic!("Could not get config dir"), + } +} + +pub fn get_config() -> Config { + let default_config = get_default_config(); + let config_path = get_config_path(); + + let config_dir = get_config_dir(); + + if !config_dir.exists() { + fs::create_dir_all(&config_dir).expect("Could not create config dir"); + } + + match fs::metadata(&config_path) { + Ok(_) => { + let config = fs::read_to_string(&config_path).expect("Could not read config file"); + serde_json::from_str(&config).unwrap_or(default_config) + } + Err(_) => { + File::create(&config_path) + .expect("Could not create config file") + .write_all( + serde_json::to_string(&default_config) + .expect("Could not default serialize config") + .as_bytes(), + ) + .expect("Could not write config file"); + default_config + } + } +} + +pub fn set_config(config: Config, override_config: bool) { + let config_path = get_config_path(); + let mut current_config = get_config(); + + if override_config { + current_config = config; + } else { + current_config.merge(config); + } + + File::create(config_path) + .expect("Could not create config file") + .write_all( + serde_json::to_string(¤t_config) + .expect("Could not serialize config") + .as_bytes(), + ) + .expect("Could not write config file"); +} diff --git a/src/utils/logger.rs b/src/utils/logger.rs new file mode 100644 index 0000000..d94aedf --- /dev/null +++ b/src/utils/logger.rs @@ -0,0 +1,48 @@ +use colored::*; + +use cliclack::log; + +pub fn get_error_string(err: &str, with_prefix: bool) -> String { + format!( + "{}{}", + match with_prefix { + true => format!("{} ", " ERROR ".on_red().black()), + false => "".to_string(), + }, + err.red() + ) +} + +pub fn get_success_string(msg: &str, with_prefix: bool) -> String { + format!( + "{}{}", + match with_prefix { + true => format!("{} ", " SUCCESS ".on_green().black()), + false => "".to_string(), + }, + msg.green() + ) +} + +pub fn get_info_string(msg: &str, with_prefix: bool) -> String { + format!( + "{}{}", + match with_prefix { + true => format!("{} ", " INFO ".on_cyan().black()), + false => "".to_string(), + }, + msg.cyan() + ) +} + +pub fn error(err: &str, with_prefix: bool) { + log::error(get_error_string(err, with_prefix)).unwrap(); +} + +pub fn success(msg: &str, with_prefix: bool) { + log::success(get_success_string(msg, with_prefix)).unwrap(); +} + +pub fn info(msg: &str, with_prefix: bool) { + log::info(get_info_string(msg, with_prefix)).unwrap(); +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs new file mode 100644 index 0000000..3779188 --- /dev/null +++ b/src/utils/mod.rs @@ -0,0 +1,81 @@ +mod logger; + +use cliclack::{intro, outro, outro_cancel}; +use regex::Regex; +use std::{ + env, + path::PathBuf, + process::{self, Command}, +}; + +use crate::store::get_config; + +pub fn is_neovim_installed() -> bool { + Command::new("nvim").arg("--version").output().is_ok() +} + +pub fn is_fzf_installed() -> bool { + Command::new("fzf").arg("--version").output().is_ok() +} + +pub fn print_intro(msg: Option<&str>) { + intro( + msg.unwrap_or("Neovim Configuration Switcher") + .to_uppercase(), + ) + .unwrap(); +} + +pub fn print_outro(msg: Option<&str>) { + outro(logger::get_success_string( + msg.unwrap_or("Thanks for using Neovim Configuration Switcher!"), + false, + )) + .unwrap(); +} + +pub fn print_outro_cancel(msg: &str) { + outro_cancel(logger::get_error_string(msg, true)).unwrap(); + process::exit(0); +} + +/// Workaround to enable [console::Emoji]. Disable it with [disable_emojis] +pub fn enable_emojis() { + match env::var("WT_SESSION") { + Ok(_) => {} + Err(_) => env::set_var("WT_SESSION", "nvims-wt-session-hack"), + } +} + +/// Workaround to disable [console::Emoji] after enabling it with [enable_emojis] +pub fn disable_emojis() { + if env::var("WT_SESSION").unwrap_or("".to_string()) == *"nvims-wt-session-hack" { + env::remove_var("WT_SESSION"); + }; +} + +pub fn is_valid_github_url(url: &str) -> bool { + let re = Regex::new(r"^(https?://github\.com/|git@github\.com:)[^/\s]+/[^/\s]+(\.git)?$") + .expect("Failed to validate GitHub URL"); + re.is_match(url) +} + +pub fn get_nvim_config_dir(path: Option<&str>) -> PathBuf { + let config_dir = dirs::config_local_dir().expect("Could not get config dir"); + if let Some(path) = path { + config_dir.join(path) + } else { + config_dir + } +} + +pub fn print_empty_configurations() -> bool { + let config = get_config(); + if config.configs.is_empty() { + print_intro(None); + print_outro_cancel("No configurations found! Add a configuration and try again."); + true + } else { + false + } +}