diff --git a/Cargo.lock b/Cargo.lock index 8534123..549e55c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,637 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "3.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83" -dependencies = [ - "atty", - "bitflags", - "clap_derive", - "clap_lex", - "indexmap", - "once_cell", - "strsim", - "termcolor", - "textwrap", -] - -[[package]] -name = "clap_derive" -version = "3.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759bf187376e1afa7b85b959e6a664a3e7a95203415dba952ad19139e798f902" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "crossterm" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2102ea4f781910f8a5b98dd061f4c2023f479ce7bb1236330099ceb5a93cf17" -dependencies = [ - "bitflags", - "crossterm_winapi", - "libc", - "mio", - "parking_lot", - "signal-hook", - "signal-hook-mio", - "winapi", -] - -[[package]] -name = "crossterm_winapi" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" -dependencies = [ - "winapi", -] - -[[package]] -name = "difflib" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" - -[[package]] -name = "downcast" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" - -[[package]] -name = "either" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" - -[[package]] -name = "float-cmp" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" -dependencies = [ - "num-traits", -] - -[[package]] -name = "fragile" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85dcb89d2b10c5f6133de2efd8c11959ce9dbb46a2f7a4cab208c4eeda6ce1ab" - -[[package]] -name = "getrandom" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "hashbrown" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" - -[[package]] -name = "heck" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "indexmap" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "itertools" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" -dependencies = [ - "either", -] - -[[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.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" - -[[package]] -name = "lock_api" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "mio" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys", -] - -[[package]] -name = "mockall" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5641e476bbaf592a3939a7485fa079f427b4db21407d5ebfd5bba4e07a1f6f4c" -dependencies = [ - "cfg-if", - "downcast", - "fragile", - "lazy_static", - "mockall_derive", - "predicates", - "predicates-tree", -] - -[[package]] -name = "mockall_derive" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "262d56735932ee0240d515656e5a7667af3af2a5b0af4da558c4cff2b2aeb0c7" -dependencies = [ - "cfg-if", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "normalize-line-endings" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac8b1a9b2518dc799a2271eff1688707eb315f0d4697aa6b0871369ca4c4da55" - -[[package]] -name = "os_str_bytes" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" - -[[package]] -name = "predicates" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c" -dependencies = [ - "difflib", - "float-cmp", - "itertools", - "normalize-line-endings", - "predicates-core", - "regex", -] - -[[package]] -name = "predicates-core" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da1c2388b1513e1b605fcec39a95e0a9e8ef088f71443ef37099fa9ae6673fcb" - -[[package]] -name = "predicates-tree" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d86de6de25020a36c6d3643a86d9a6a9f552107c0559c60ea03551b5e16c032" -dependencies = [ - "predicates-core", - "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.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "signal-hook" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-mio" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" -dependencies = [ - "libc", - "mio", - "signal-hook", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" -dependencies = [ - "libc", -] - -[[package]] -name = "smallvec" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "syn" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "termtree" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b" - -[[package]] -name = "textwrap" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" - -[[package]] -name = "unicode-ident" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - [[package]] name = "wipe" -version = "1.0.1" -dependencies = [ - "anyhow", - "clap", - "crossterm", - "mockall", - "rand", -] +version = "2.0.0" diff --git a/Cargo.toml b/Cargo.toml index 2503b1b..d959742 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,21 +1,7 @@ -# Don't forget to update -# - dist/arch/PKGBUILD -# - dist/deb/build - [package] name = "wipe" -version = "1.0.1" +version = "2.0.0" edition = "2021" license = "MIT" -description = "Wipe your terminal with a random animation." repository = "https://github.com/ricoriedel/wipe" -authors = ["Rico Riedel"] - -[dependencies] -anyhow = "1.0" -clap = { version = "3.2", features = ["derive"]} -crossterm = "0.23" -rand = "0.8" - -[dev-dependencies] -mockall = "0.11" \ No newline at end of file +authors = ["Rico Riedel"] \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index e7dda0a..0000000 --- a/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# Wipe -Wipe your terminal with a smooth animation. - -This is the perfect program for you, if you like `clear` but want to add an unnecessary animation. - -Download options can be found in the [release tab](https://github.com/ricoriedel/wipe/releases). - -## Configuration -All configuration is done using command line parameters. -For a list of parameters, execute `wipe -h`. -Note that some parameters like `--color` can be specified multiple times with different values. - -If you want a persistent solution, you can add an alias to your `.bashrc` equivalent. -```shell -# Persistent config -alias wipe='wipe -c red' - -# Replace clear with wipe -alias clear='wipe' -``` - -If you are using `ZSH` as your shell, you can add a keyboard shortcut like this: -```shell -# Bind wipe to CTRL+W -wipe-zle() { - wipe - zle reset-prompt -} -zle -N wipe-zle -bindkey '^w' wipe-zle -``` - -## Showcase -[![Circle](doc/circle.gif)]() -[![Rhombus](doc/rhombus.gif)]() -[![Rotation](doc/sonar.gif)]() diff --git a/dist/arch/PKGBUILD b/dist/arch/PKGBUILD deleted file mode 100644 index 2bf36ed..0000000 --- a/dist/arch/PKGBUILD +++ /dev/null @@ -1,37 +0,0 @@ -# Maintainer: Rico Riedel - -pkgname='wipe-terminal-git' -pkgver='1.0.1' -pkgrel='4' -pkgdesc='Wipe your terminal with a random animation.' -arch=('x86_64') -url='https://github.com/ricoriedel/wipe' -license=('MIT') -makedepends=('cargo') -conflicts=('wipe') -source=('git+https://www.github.com/ricoriedel/wipe.git') -sha256sums=('SKIP') - -prepare() { - cd wipe - cargo fetch --locked --target "$CARCH-unknown-linux-gnu" -} - -build() { - cd wipe - export RUSTUP_TOOLCHAIN=stable - export CARGO_TARGET_DIR=target - cargo build --frozen --release --all-features -} - -check() { - cd wipe - export RUSTUP_TOOLCHAIN=stable - cargo test --frozen --all-features -} - -package() { - cd wipe - install -Dm0644 -t "$pkgdir/usr/share/licenses/$pkgname/" 'LICENSE' - install -Dm0755 -t "$pkgdir/usr/bin/" "target/release/wipe" -} \ No newline at end of file diff --git a/dist/deb/build b/dist/deb/build deleted file mode 100755 index 2467b60..0000000 --- a/dist/deb/build +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash -set -e - -pkgname='wipe-terminal' -version='1.0.1-4' -maintainer='Rico Riedel ' -description='Wipe your terminal with a random animation.' -arch='x86_64' -debarch='amd64' -pkgdir="$PWD/$pkgname" -srcdir="$PWD/../.." - -build() { - cd "$srcdir" - - export RUSTUP_TOOLCHAIN=stable - export CARGO_TARGET_DIR=target - - cargo fetch --locked --target "$arch-unknown-linux-gnu" - cargo build --frozen --release --all-features - cargo test --frozen --all-features -} - -package() { - cd "$srcdir" - - install -Dm0644 'LICENSE' "$pkgdir/usr/share/doc/$pkgname/copyright" - install -Dm0755 -t "$pkgdir/usr/bin/" "target/release/wipe" - - mkdir -p "$pkgdir/DEBIAN" - echo "Package: $pkgname" > "$pkgdir/DEBIAN/control" - echo "Version: $version" >> "$pkgdir/DEBIAN/control" - echo "Section: utils" >> "$pkgdir/DEBIAN/control" - echo "Priority: optional" >> "$pkgdir/DEBIAN/control" - echo "Architecture: $debarch" >> "$pkgdir/DEBIAN/control" - echo "Maintainer: $maintainer" >> "$pkgdir/DEBIAN/control" - echo "Description: $description" >> "$pkgdir/DEBIAN/control" - - dpkg-deb --root-owner-group --build "$pkgdir" -} - -mkdir -p "$pkgdir" - -build -package diff --git a/dist/win/build b/dist/win/build deleted file mode 100755 index e1fc784..0000000 --- a/dist/win/build +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash -set -e - -target='x86_64-pc-windows-gnu' -pkgdir="$PWD" -pkgfile="$pkgdir/win.zip" -srcdir="$PWD/../.." - -build() { - cd "$srcdir" - - export RUSTUP_TOOLCHAIN=stable - export CARGO_TARGET_DIR=target - - cargo fetch --locked --target "$target" - cargo build --frozen --release --all-features --target "$target" - cargo test --frozen --all-features -} - -package() { - cd "$srcdir" - cp "target/$target/release/wipe.exe" "$pkgdir" - cp 'LICENSE' "$pkgdir" - - cd "$pkgdir" - zip -m "$pkgfile" 'wipe.exe' 'LICENSE' -} - -build -package \ No newline at end of file diff --git a/doc/circle.gif b/doc/circle.gif deleted file mode 100644 index cd9f649..0000000 Binary files a/doc/circle.gif and /dev/null differ diff --git a/doc/rhombus.gif b/doc/rhombus.gif deleted file mode 100644 index acba5f5..0000000 Binary files a/doc/rhombus.gif and /dev/null differ diff --git a/doc/sonar.gif b/doc/sonar.gif deleted file mode 100644 index 5359849..0000000 Binary files a/doc/sonar.gif and /dev/null differ diff --git a/src/animation/circle.rs b/src/animation/circle.rs deleted file mode 100644 index d41c018..0000000 --- a/src/animation/circle.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::animation::Animation; -use crate::vec::Vector; - -const THICKNESS: f32 = 0.2; -const FINAL_RADIUS: f32 = 1.0 + THICKNESS * 2.0; - -/// An animation of an expanding circle. -pub struct CircleAnimation { - center: Vector, - thickness: f32, - final_radius: f32, -} - -impl CircleAnimation { - pub fn new(size: Vector) -> Self { - let center = size.center(); - let distance = center.length(); - - Self { - center, - thickness: distance * THICKNESS, - final_radius: distance * FINAL_RADIUS, - } - } -} - -impl Animation for CircleAnimation { - fn sample(&self, step: f32, pos: Vector) -> f32 { - let radius = self.final_radius * step - self.thickness; - let distance = (pos - self.center).length(); - - (distance - radius) / self.thickness - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn sample() { - let anim = CircleAnimation::new(Vector::new(10.0, 20.0)); - - let sample_1 = anim.sample(0.5, Vector::new(17.0, 5.0)); - let sample_2 = anim.sample(0.8, Vector::new(11.0, 8.0)); - let sample_3 = anim.sample(0.2, Vector::new(7.0, 10.0)); - - assert!(3.3 < sample_1 && sample_1 < 3.4); - assert!(-1.8 < sample_2 && sample_2 < -1.7); - assert!(0.4 < sample_3 && sample_3 < 0.5); - } -} \ No newline at end of file diff --git a/src/animation/mod.rs b/src/animation/mod.rs deleted file mode 100644 index 00b76ac..0000000 --- a/src/animation/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -pub mod circle; -pub mod sonar; -pub mod rhombus; - -use crate::vec::Vector; - -#[cfg(test)] -use mockall::automock; - -/// A sampler for an animation. -#[cfg_attr(test, automock)] -pub trait Animation { - /// Returns the level (of brightness) for the - /// given step of the animation an position on screen. - /// # Arguments - /// * `step`: `0 <= step` and `step <= 1` - /// - /// # Return values - /// * `1 < n` => Keep current character - /// * `0 <= n` and `n < 1` => Draw some character - /// * `n < 0` => Clear character - fn sample(&self, step: f32, pos: Vector) -> f32; -} \ No newline at end of file diff --git a/src/animation/rhombus.rs b/src/animation/rhombus.rs deleted file mode 100644 index 54a0507..0000000 --- a/src/animation/rhombus.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::animation::Animation; -use crate::vec::Vector; - -const THICKNESS: f32 = 0.2; -const FINAL_DISTANCE: f32 = 1.0 + THICKNESS * 2.0; - -/// An animation of an expanding rhombus. -pub struct RhombusAnimation { - center: Vector, - thickness: f32, - final_distance: f32, -} - -impl RhombusAnimation { - pub fn new(size: Vector) -> Self { - let center = size.center(); - let distance = center.sum(); - - Self { - center, - thickness: distance * THICKNESS, - final_distance: distance * FINAL_DISTANCE, - } - } -} - -impl Animation for RhombusAnimation { - fn sample(&self, step: f32, pos: Vector) -> f32 { - let dist = self.final_distance * step - self.thickness; - let pos_dist = (self.center - pos).abs().sum(); - - (pos_dist - dist) / self.thickness - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn sample() { - let anim = RhombusAnimation::new(Vector::new(30.0, 10.0)); - - let sample_1 = anim.sample(0.2, Vector::new(5.0, 16.0)); - let sample_2 = anim.sample(0.7, Vector::new(22.0, 2.0)); - let sample_3 = anim.sample(0.5, Vector::new(4.0, 7.0)); - - assert!(4.8 < sample_1 && sample_1 < 4.9); - assert!(-1.5 < sample_2 && sample_2 < -1.4); - assert!(0.7 < sample_3 && sample_3 < 0.8); - } -} \ No newline at end of file diff --git a/src/animation/sonar.rs b/src/animation/sonar.rs deleted file mode 100644 index c30f6d1..0000000 --- a/src/animation/sonar.rs +++ /dev/null @@ -1,47 +0,0 @@ -use std::f32::consts::PI; -use crate::animation::Animation; -use crate::vec::Vector; - -const TWO_PI: f32 = PI * 2.0; -const THICKNESS: f32 = TWO_PI * 0.1; -const FULL_ROTATION: f32 = TWO_PI + THICKNESS * 2.0; - -/// A sonar like animation. -pub struct SonarAnimation { - center: Vector -} - -impl SonarAnimation { - pub fn new(size: Vector) -> Self { - Self { - center: size.center() - } - } -} - -impl Animation for SonarAnimation { - fn sample(&self, step: f32, pos: Vector) -> f32 { - let angle = FULL_ROTATION * step - PI - THICKNESS; - let pos_angle = (pos - self.center).angle(); - - (pos_angle - angle) / THICKNESS - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn sample() { - let anim = SonarAnimation::new(Vector::new(30.0, 10.0)); - - let sample_1 = anim.sample(0.3, Vector::new(16.0, 3.0)); - let sample_2 = anim.sample(0.7, Vector::new(22.0, 2.0)); - let sample_3 = anim.sample(0.5, Vector::new(4.0, 7.0)); - - assert!(0.6 < sample_1 && sample_1 < 0.7); - assert!(-3.1 < sample_2 && sample_2 < -3.0); - assert!(4.7 < sample_3 && sample_3 < 4.8); - } -} \ No newline at end of file diff --git a/src/array.rs b/src/array.rs deleted file mode 100644 index 66f3f06..0000000 --- a/src/array.rs +++ /dev/null @@ -1,98 +0,0 @@ -use std::ops::{Index, IndexMut}; - -/// A two dimensional statically size array. -pub struct Array2D { - width: usize, - height: usize, - values: Vec -} - -impl Array2D { - pub fn new(width: usize, height: usize) -> Self { - Self { - width, - height, - values: vec![T::default(); width * height] - } - } - - pub fn width(&self) -> usize { - self.width - } - - pub fn height(&self) -> usize { - self.height - } - - /// Calculates the physical index of the given position. - /// - /// # Panics - /// Panics if the position is out of bounds. - fn index_of(&self, pos: (usize, usize)) -> usize { - assert!(pos.0 < self.width); - assert!(pos.1 < self.height); - pos.0 + pos.1 * self.width - } -} - -impl Index<(usize, usize)> for Array2D { - type Output = T; - - fn index(&self, pos: (usize, usize)) -> &Self::Output { - unsafe { self.values.get_unchecked(self.index_of(pos)) } - } -} - -impl IndexMut<(usize, usize)> for Array2D { - fn index_mut(&mut self, pos: (usize, usize)) -> &mut Self::Output { - let i = self.index_of(pos); - - unsafe { self.values.get_unchecked_mut(i) } - } -} - -#[cfg(test)] -mod test { - use crate::array::Array2D; - - #[test] - fn width() { - let array = Array2D::<()>::new(10, 4); - - assert_eq!(10, array.width()); - } - - #[test] - fn height() { - let array = Array2D::<()>::new(2, 5); - - assert_eq!(5, array.height()); - } - - #[test] - fn index() { - let mut array = Array2D::new(4, 4); - - array[(1, 2)] = 3; - array[(3, 3)] = 7; - - assert_eq!(3, array[(1, 2)]); - assert_eq!(7, array[(3, 3)]); - } - - #[test] - #[should_panic] - fn index_oob_width() { - let array = Array2D::<()>::new(5, 10); - - array[(8, 2)]; - } - - #[test] - #[should_panic] - fn index_oob_height() { - let array = Array2D::<()>::new(10, 5); - - array[(3, 7)]; - } -} \ No newline at end of file diff --git a/src/char.rs b/src/char.rs deleted file mode 100644 index 4bac492..0000000 --- a/src/char.rs +++ /dev/null @@ -1,62 +0,0 @@ -#[cfg(test)] -use mockall::automock; - -/// Used to get a character with a given brightness. -#[cfg_attr(test, automock)] -pub trait CharSampler { - /// Gets a character with the given brightness. - /// # Arguments - /// * `level`: `0 <= level` and `level < 1` - fn sample(&self, level: f32) -> char; -} - -pub struct SimpleCharSampler { - len: f32, - chars: String -} - -impl SimpleCharSampler { - /// # Arguments - /// * `chars`: The characters ordered by brightness. - pub fn new(chars: String) -> Self { - let len = chars.chars().count() as f32; - - Self { chars, len } - } -} - -impl CharSampler for SimpleCharSampler { - fn sample(&self, level: f32) -> char { - assert!(0.0 <= level && level < 1.0); - - let index = level * self.len; - - self.chars.chars().nth(index as usize).unwrap() - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn sample() { - let sampler = SimpleCharSampler::new("abc".to_string()); - - assert_eq!('a', sampler.sample(0.1)); - assert_eq!('b', sampler.sample(0.4)); - assert_eq!('c', sampler.sample(0.7)); - } - - #[test] - #[should_panic] - fn sample_index_negative() { - SimpleCharSampler::new("abc".to_string()).sample(-0.1); - } - - #[test] - #[should_panic] - fn sample_index_equals_one() { - SimpleCharSampler::new("abc".to_string()).sample(1.0); - } -} \ No newline at end of file diff --git a/src/choose.rs b/src/choose.rs deleted file mode 100644 index c9dff80..0000000 --- a/src/choose.rs +++ /dev/null @@ -1,66 +0,0 @@ -use rand::prelude::IteratorRandom; -use rand::Rng; - -/// A trait to get all values of an enum. -pub trait Collection { - /// Returns a list of all enum values. - fn all() -> Vec where Self: Sized; -} - -/// Choose a enum from a list of options. -pub struct Chooser { - rng: TRng -} - -impl Chooser { - pub fn new(rng: TRng) -> Self { - Self { rng } - } - - /// Choose an enum item from the provided [Vec]. - /// If none are provided, a random one of all enum values is chosen. - pub fn choose(&mut self, selection: Vec) -> TValue { - let options = if selection.is_empty() { - TValue::all() - } else { - selection - }; - options.into_iter().choose_stable(&mut self.rng).unwrap() - } -} - -#[cfg(test)] -mod test { - use rand::rngs::mock::StepRng; - use crate::{Chooser, Collection}; - - enum MockOptions { - First, - Second, - Third - } - - impl Collection for MockOptions { - fn all() -> Vec where Self: Sized { - use MockOptions::*; - - vec![First, Second, Third] - } - } - - #[test] - fn choose() { - let rng = StepRng::new(0, 1); - let mut chooser = Chooser::new(rng); - - assert!(matches!(chooser.choose(vec![MockOptions::First, MockOptions::Second]), MockOptions::Second)); - } - - #[test] - fn choose_empty() { - let rng = StepRng::new(0, 1); - let mut chooser = Chooser::new(rng); - - assert!(matches!(chooser.choose(Vec::new()), MockOptions::Third)); - } -} \ No newline at end of file diff --git a/src/color.rs b/src/color.rs deleted file mode 100644 index 130fd66..0000000 --- a/src/color.rs +++ /dev/null @@ -1,61 +0,0 @@ -use crossterm::style::Color; - -#[cfg(test)] -use mockall::automock; - -/// A collection of colors. -#[cfg_attr(test, automock)] -pub trait ColorSampler { - /// Gets a color for the given fill. - /// # Arguments - /// * `fill`: `0 <= fill` and `fill < 1` - fn sample(&self, fill: f32) -> Color; -} - -/// A simple color sampler which interpolates the color from a [Vec]. -pub struct SimpleColorSampler { - values: Vec -} - -impl SimpleColorSampler { - pub fn new(values: Vec) -> Self { - Self { values } - } -} - -impl ColorSampler for SimpleColorSampler { - fn sample(&self, fill: f32) -> Color { - assert!(0.0 <= fill && fill < 1.0); - - let index = self.values.len() as f32 * fill; - - self.values[index as usize] - } -} - -#[cfg(test)] -mod test { - use crossterm::style::Color::*; - use super::*; - - #[test] - fn sample() { - let sampler = SimpleColorSampler::new(vec![Red, Yellow, Green]); - - assert_eq!(Red, sampler.sample(0.1)); - assert_eq!(Yellow, sampler.sample(0.4)); - assert_eq!(Green, sampler.sample(0.7)); - } - - #[test] - #[should_panic] - fn sample_index_negative() { - SimpleColorSampler::new(Vec::new()).sample(-0.1); - } - - #[test] - #[should_panic] - fn sample_index_equals_one() { - SimpleColorSampler::new(Vec::new()).sample(1.0); - } -} \ No newline at end of file diff --git a/src/fill/circle.rs b/src/fill/circle.rs deleted file mode 100644 index 513e0db..0000000 --- a/src/fill/circle.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::fill::FillMode; -use crate::vec::Vector; - -const INTERVAL: f32 = 4.0; - -/// Fill based on rings of a circle. -pub struct CircleFillMode { - center: Vector, - interval: f32 -} - -impl CircleFillMode { - pub fn new(size: Vector) -> Self { - Self { - center: size.center(), - interval: size.smaller() / INTERVAL, - } - } -} - -impl FillMode for CircleFillMode { - fn sample(&self, _: f32, pos: Vector) -> f32 { - ((pos - self.center).length() % self.interval) / self.interval - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn sample() { - let fill = CircleFillMode::new(Vector::new(10.0, 8.0)); - - let sample_1 = fill.sample(0.0, Vector::new(5.0, 3.0)); - let sample_2 = fill.sample(0.0, Vector::new(8.5, 4.0)); - - assert!(0.4 < sample_1 && sample_1 < 0.6); - assert!(0.7 < sample_2 && sample_2 < 0.8); - } -} \ No newline at end of file diff --git a/src/fill/level.rs b/src/fill/level.rs deleted file mode 100644 index 394ae18..0000000 --- a/src/fill/level.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::fill::FillMode; -use crate::vec::Vector; - -/// Fill based on the level of brightness. -pub struct LevelFillMode; - -impl LevelFillMode { - pub fn new() -> Self { - Self { } - } -} - -impl FillMode for LevelFillMode { - fn sample(&self, level: f32, _: Vector) -> f32 { - level - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn sample() { - let mode = LevelFillMode::new(); - - assert_eq!(0.3, mode.sample(0.3, Vector::new(0.0, 0.0))); - assert_eq!(0.7, mode.sample(0.7, Vector::new(0.1, 0.2))); - } -} \ No newline at end of file diff --git a/src/fill/mod.rs b/src/fill/mod.rs deleted file mode 100644 index d3cf5d5..0000000 --- a/src/fill/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -pub mod level; -pub mod circle; -pub mod stripes; - -use crate::vec::Vector; - -#[cfg(test)] -use mockall::automock; - -/// Used to choose the colors of characters. -#[cfg_attr(test, automock)] -pub trait FillMode { - /// Gets the color for this character. - /// # Arguments - /// * `step`: `0 <= step` and `step <= 1` - fn sample(&self, level: f32, pos: Vector) -> f32; -} \ No newline at end of file diff --git a/src/fill/stripes.rs b/src/fill/stripes.rs deleted file mode 100644 index c50c3e6..0000000 --- a/src/fill/stripes.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::FillMode; -use crate::vec::Vector; - -const INTERVAL: f32 = 4.0; - -/// Fill based on diagonal stripes. -pub struct StripesFillMode { - interval: f32 -} - -impl StripesFillMode { - pub fn new(size: Vector) -> Self { - Self { - interval: size.smaller() / INTERVAL - } - } -} - -impl FillMode for StripesFillMode { - fn sample(&self, _: f32, pos: Vector) -> f32 { - (pos.sum() % self.interval) / self.interval - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn sample() { - let mode = StripesFillMode::new(Vector::new(8.0, 4.0)); - - assert_eq!(0.25, mode.sample(0.0, Vector::new(1.5, 0.75))); - assert_eq!(0.5, mode.sample(0.0, Vector::new(4.0, 2.5))); - } -} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 572d778..e7a11a9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,288 +1,3 @@ -use std::io::stdout; -use std::time::Duration; -use anyhow::{anyhow, Error}; -use clap::Parser; -use clap::ArgEnum; -use rand::rngs::OsRng; -use crate::animation::Animation; -use crate::animation::circle::CircleAnimation; -use crate::animation::rhombus::RhombusAnimation; -use crate::animation::sonar::SonarAnimation; -use crate::char::SimpleCharSampler; -use crate::choose::{Chooser, Collection}; -use crate::color::{ColorSampler, SimpleColorSampler}; -use crate::fill::circle::CircleFillMode; -use crate::fill::FillMode; -use crate::fill::level::LevelFillMode; -use crate::fill::stripes::StripesFillMode; -use crate::render::{Renderer, SamplerRenderer}; -use crate::runner::Runner; -use crate::sampler::ComposedSampler; -use crate::surface::WriteSurface; -use crate::timer::SimpleTimer; -use crate::vec::Vector; - -mod color; -mod char; -mod fill; -mod vec; -mod array; -mod surface; -mod animation; -mod sampler; -mod render; -mod timer; -mod runner; -mod choose; - -/// Defines an enum and implements the [Collection] trait. -macro_rules! options { - ($name:ident { $($opt:ident,)* }) => { - #[derive(Copy, Clone, ArgEnum)] - enum $name { - $($opt,)* - } - impl Collection for $name { - fn all() -> Vec { - vec![$($name::$opt,)*] - } - } - } +fn main() { + println!("Hello, world!"); } - -options!(AnimationType { - Circle, - Rhombus, - Sonar, -}); - -options!(ColorType { - Red, - Green, - Blue, - LightRed, - LightGreen, - LightBlue, - Grey, - Rainbow, -}); - -options!(FillModeType { - Circle, - Level, - Stripes, -}); - -const MAX_FPS: u64 = 480; - -/// The program arguments. -#[derive(Parser)] -#[clap(author = env ! ("CARGO_PKG_AUTHORS"), version = env ! ("CARGO_PKG_VERSION"), about = env ! ("CARGO_PKG_DESCRIPTION"))] -struct Args { - #[clap(short, long, help = "Add animation", arg_enum)] - animation: Vec, - #[clap(short, long, help = "Add fill mode", arg_enum)] - fill: Vec, - #[clap(short, long, help = "Add color pallet", arg_enum)] - color: Vec, - #[clap(long, default_value = ".-+%#", parse(try_from_str = validate_chars), help = "Set chars")] - chars: String, - #[clap(long, default_value = "30", parse(try_from_str = validate_fps), help = "Set frames per second [max: 480]")] - fps: u64, - #[clap(long, default_value = "1000", parse(try_from_str = validate_duration), help = "Set duration [milliseconds]")] - duration: u64, - #[clap(long, help = "Set width [default: terminal width]")] - width: Option, - #[clap(long, help = "Set height [default: terminal height]")] - height: Option, -} - -fn main() -> Result<(), Error> { - let args = Args::parse(); - let mut chooser = Chooser::new(OsRng::default()); - - let (width, height) = size(crossterm::terminal::size()?, args.width, args.height); - let size = Vector::from_terminal(width, height); - let delay = delay_of_fps(args.fps); - let duration = Duration::from_millis(args.duration); - - let animation = create_animation(chooser.choose(args.animation), size); - let fill = create_fill(chooser.choose(args.fill), size); - let color = create_color(chooser.choose(args.color)); - let char = Box::new(SimpleCharSampler::new(args.chars)); - - let sampler = ComposedSampler::new(animation, fill, color, char); - let surface = WriteSurface::new(stdout(), width, height)?; - - let renderer = SamplerRenderer::new(surface, sampler); - let timer = SimpleTimer::new(delay); - let runner = Runner::new(duration, timer, renderer); - - runner.run() -} - -/// Validates the chars argument. -fn validate_chars(text: &str) -> Result { - if text.is_empty() { - Err(anyhow!("can't be empty.")) - } else { - Ok(text.to_string()) - } -} - -/// Validates the fps argument. -fn validate_fps(text: &str) -> Result { - let value = text.parse()?; - - if value > MAX_FPS { - Err(anyhow!("value is above limit of {}.", MAX_FPS)) - } else if value == 0 { - Err(anyhow!("value is zero.")) - } else { - Ok(value) - } -} - -/// Validates the duration argument. -fn validate_duration(text: &str) -> Result { - let value = text.parse()?; - - if value == 0 { - Err(anyhow!("value is zero.")) - } else { - Ok(value) - } -} - -/// Returns the size to use based on the terminal size and width and height arguments. -fn size(terminal: (u16, u16), width: Option, height: Option) -> (usize, usize) { - let width = width.unwrap_or(terminal.0 as usize); - let height = height.unwrap_or(terminal.1 as usize); - (width, height) -} - -/// Calculates the delay between frames based on the fps. -fn delay_of_fps(fps: u64) -> Duration { - Duration::from_nanos(1_000_000_000 / fps) -} - -fn create_animation(animation: AnimationType, size: Vector) -> Box { - match animation { - AnimationType::Circle => Box::new(CircleAnimation::new(size)), - AnimationType::Rhombus => Box::new(RhombusAnimation::new(size)), - AnimationType::Sonar => Box::new(SonarAnimation::new(size)), - } -} - -fn create_fill(fill: FillModeType, size: Vector) -> Box { - match fill { - FillModeType::Circle => Box::new(CircleFillMode::new(size)), - FillModeType::Level => Box::new(LevelFillMode::new()), - FillModeType::Stripes => Box::new(StripesFillMode::new(size)) - } -} - -fn create_color(color: ColorType) -> Box { - use crossterm::style::Color::*; - - match color { - ColorType::Red => Box::new(SimpleColorSampler::new(vec![Yellow, DarkYellow, Red])), - ColorType::Green => Box::new(SimpleColorSampler::new(vec![Cyan, DarkGreen, Green])), - ColorType::Blue => Box::new(SimpleColorSampler::new(vec![Magenta, DarkBlue, Blue])), - ColorType::LightRed => Box::new(SimpleColorSampler::new(vec![White, Yellow, Red])), - ColorType::LightGreen => Box::new(SimpleColorSampler::new(vec![White, Cyan, Green])), - ColorType::LightBlue => Box::new(SimpleColorSampler::new(vec![White, Blue, Magenta])), - ColorType::Grey => Box::new(SimpleColorSampler::new(vec![Black, Grey, White])), - ColorType::Rainbow => Box::new(SimpleColorSampler::new(vec![Magenta, Blue, Green, Yellow, Red])) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn validate_chars_some_string() { - assert_eq!("abc", &validate_chars("abc").unwrap()); - } - - #[test] - fn validate_chars_empty() { - assert!(validate_chars("").is_err()); - } - - #[test] - fn validate_fps_some_string() { - assert_eq!(35, validate_fps("35").unwrap()); - } - - #[test] - fn validate_fps_zero() { - assert!(validate_fps("0").is_err()); - } - - #[test] - fn validate_fps_above_max() { - assert!(validate_fps("500").is_err()); - } - - #[test] - fn validate_duration_some_string() { - assert_eq!(500, validate_duration("500").unwrap()); - } - - #[test] - fn validate_duration_zero() { - assert!(validate_duration("0").is_err()); - } - - #[test] - fn size_not_set() { - assert_eq!((4, 6), size((4, 6), None, None)); - } - - #[test] - fn size_width_set() { - assert_eq!((8, 3), size((2, 3), Some(8), None)); - } - - #[test] - fn size_height_set() { - assert_eq!((1, 6), size((1, 7), None, Some(6))); - } - - #[test] - fn delay_of_fps_some_number() { - assert_eq!(Duration::from_nanos(10_526_315), delay_of_fps(95)); - } - - #[test] - fn create_animation_all_implemented() { - let size = Vector::new(0.0, 0.0); - - create_animation(AnimationType::Circle, size); - create_animation(AnimationType::Rhombus, size); - create_animation(AnimationType::Sonar, size); - } - - #[test] - fn create_fill_all_implemented() { - let size = Vector::new(0.0, 0.0); - - create_fill(FillModeType::Circle, size); - create_fill(FillModeType::Level, size); - create_fill(FillModeType::Stripes, size); - } - - #[test] - fn create_color_all_implemented() { - create_color(ColorType::Red); - create_color(ColorType::Green); - create_color(ColorType::Blue); - create_color(ColorType::LightRed); - create_color(ColorType::LightGreen); - create_color(ColorType::LightBlue); - create_color(ColorType::Grey); - create_color(ColorType::Rainbow); - } -} \ No newline at end of file diff --git a/src/render.rs b/src/render.rs deleted file mode 100644 index d0b922f..0000000 --- a/src/render.rs +++ /dev/null @@ -1,95 +0,0 @@ -use anyhow::Error; -use crate::sampler::{Sample, Sampler}; -use crate::surface::Surface; -use crate::Vector; - -#[cfg(test)] -use mockall::automock; - -/// A trait for anything which performs some rendering. -#[cfg_attr(test, automock)] -pub trait Renderer { - /// Render the frame. - fn render(&mut self, step: f32); - - /// Present the finished frame. - fn present(&mut self) -> Result<(), Error>; -} - -/// Fills its [Surface] with the values received from a [Sampler]. -pub struct SamplerRenderer { - surface: TSurface, - sampler: TSampler, -} - -impl SamplerRenderer { - pub fn new(surface: T1, sampler: T2) -> Self { - Self { surface, sampler } - } -} - -impl Renderer for SamplerRenderer { - fn render(&mut self, step: f32) { - for x in 0..self.surface.width() { - for y in 0..self.surface.height() { - let pos = Vector::from_terminal(x, y); - let sample = self.sampler.sample(step, pos); - - match sample { - Sample::Keep => (), - Sample::Draw { char, color } => self.surface.draw(x, y, char, color), - Sample::Clear => self.surface.clear(x, y), - } - } - } - } - - fn present(&mut self) -> Result<(), Error> { - self.surface.present() - } -} - -#[cfg(test)] -mod test { - use crossterm::style::*; - use mockall::predicate::*; - use super::*; - use crate::surface::MockSurface; - use crate::sampler::MockSampler; - - #[test] - fn render() { - let mut surface = MockSurface::new(); - let mut sampler = MockSampler::new(); - - sampler.expect_sample().withf(|_, pos| pos.x == 0.0 && pos.y == 0.0).returning(|_,_| Sample::Clear); - sampler.expect_sample().withf(|_, pos| pos.x == 1.0 && pos.y == 0.0).returning(|_,_| Sample::Keep); - sampler.expect_sample().withf(|_, pos| pos.x == 0.0 && pos.y == 2.0).returning(|_,_| Sample::Draw { char: 'a', color: Color::Red }); - sampler.expect_sample().withf(|_, pos| pos.x == 1.0 && pos.y == 2.0).returning(|_,_| Sample::Keep); - sampler.expect_sample().withf(|_, pos| pos.x == 0.0 && pos.y == 4.0).returning(|_,_| Sample::Draw { char: 'x', color: Color::Yellow }); - sampler.expect_sample().withf(|_, pos| pos.x == 1.0 && pos.y == 4.0).returning(|_,_| Sample::Clear); - - surface.expect_width().return_const(2 as usize); - surface.expect_height().return_const(3 as usize); - surface.expect_clear().once().with(eq(0), eq(0)).return_const(()); - surface.expect_draw().once().with(eq(0), eq(1), eq('a'), eq(Color::Red)).return_const(()); - surface.expect_draw().once().with(eq(0), eq(2), eq('x'), eq(Color::Yellow)).return_const(()); - surface.expect_clear().once().with(eq(1), eq(2)).return_const(()); - - let mut renderer = SamplerRenderer::new(surface, sampler); - - renderer.render(0.5); - } - - #[test] - fn present() { - let mut surface = MockSurface::new(); - let sampler = MockSampler::new(); - - surface.expect_present().once().returning(|| Ok(())); - - let mut renderer = SamplerRenderer::new(surface, sampler); - - renderer.present().unwrap(); - } -} \ No newline at end of file diff --git a/src/runner.rs b/src/runner.rs deleted file mode 100644 index 1dfeddc..0000000 --- a/src/runner.rs +++ /dev/null @@ -1,73 +0,0 @@ -use std::time::Duration; -use anyhow::Error; -use crate::Renderer; -use crate::timer::Timer; - -/// Periodically calls [Renderer::render] and [Renderer::present]. -pub struct Runner { - duration: Duration, - timer: TTimer, - renderer: TRenderer, -} - -impl Runner { - pub fn new(duration: Duration, - timer: T1, - renderer: T2) -> Self { - - Self { duration, timer, renderer } - } - - pub fn run(mut self) -> Result<(), Error> { - self.timer.set(); - - while self.timer.elapsed() < self.duration { - let step = self.timer.elapsed().as_secs_f32() / self.duration.as_secs_f32(); - - self.renderer.render(step); - self.renderer.present()?; - self.timer.sleep(); - } - self.renderer.render(1.0); - self.renderer.present()?; - - Ok(()) - } -} - -#[cfg(test)] -mod test { - use std::time::Duration; - use mockall::predicate::*; - use mockall::Sequence; - use crate::timer::MockTimer; - use crate::render::MockRenderer; - use super::*; - - #[test] - fn run() { - let mut timer = MockTimer::new(); - let mut renderer = MockRenderer::new(); - let seq = &mut Sequence::new(); - - timer.expect_set().once().in_sequence(seq).return_const(()); - - timer.expect_elapsed().times(2).in_sequence(seq).return_const(Duration::from_secs(0)); - renderer.expect_render().once().with(eq(0.0)).in_sequence(seq).return_const(()); - renderer.expect_present().once().in_sequence(seq).returning(|| Ok(())); - timer.expect_sleep().once().in_sequence(seq).return_const(()); - - timer.expect_elapsed().times(2).in_sequence(seq).return_const(Duration::from_secs(2)); - renderer.expect_render().once().with(eq(0.5)).in_sequence(seq).return_const(()); - renderer.expect_present().once().in_sequence(seq).returning(|| Ok(())); - timer.expect_sleep().once().in_sequence(seq).return_const(()); - - timer.expect_elapsed().times(1).in_sequence(seq).return_const(Duration::from_secs(4)); - renderer.expect_render().once().with(eq(1.0)).in_sequence(seq).return_const(()); - renderer.expect_present().once().in_sequence(seq).returning(|| Ok(())); - - let runner = Runner::new(Duration::from_secs(4), timer, renderer); - - runner.run().unwrap(); - } -} \ No newline at end of file diff --git a/src/sampler.rs b/src/sampler.rs deleted file mode 100644 index 4712233..0000000 --- a/src/sampler.rs +++ /dev/null @@ -1,147 +0,0 @@ -use crossterm::style::Color; -use crate::animation::Animation; -use crate::char::CharSampler; -use crate::color::ColorSampler; -use crate::fill::FillMode; -use crate::vec::Vector; - -#[cfg(test)] -use mockall::automock; - -/// The action to perform for the given values. -pub enum Sample { - Keep, - Draw { char: char, color: Color }, - Clear, -} - -/// Provides a [Sample] for some values. -#[cfg_attr(test, automock)] -pub trait Sampler { - /// Get a [Sample] for the step of the animation and position on screen. - /// # Arguments - /// * `step`: `0 <= step` and `step <= 1` - fn sample(&self, step: f32, pos: Vector) -> Sample; -} - -/// Links primitive samplers into a full [Sampler]. -pub struct ComposedSampler { - animation: Box, - fill: Box, - color: Box, - char: Box, -} - -impl ComposedSampler { - pub fn new(animation: Box, - fill: Box, - color: Box, - char: Box) -> Self { - Self { animation, fill, color, char } - } -} - -impl Sampler for ComposedSampler { - fn sample(&self, step: f32, pos: Vector) -> Sample { - let level = self.animation.sample(step, pos); - - if level >= 1.0 { - Sample::Keep - } else if level >= 0.0 { - let char = self.char.sample(level); - let fill = self.fill.sample(level, pos); - let color = self.color.sample(fill); - - Sample::Draw { char, color } - } else { - Sample::Clear - } - } -} - -#[cfg(test)] -mod test { - use mockall::predicate::{always, eq}; - use super::*; - use crate::animation::MockAnimation; - use crate::fill::MockFillMode; - use crate::color::MockColorSampler; - use crate::char::MockCharSampler; - - #[test] - fn sample_keep() { - let mut anim = Box::new(MockAnimation::new()); - let fill = Box::new(MockFillMode::new()); - let color = Box::new(MockColorSampler::new()); - let char = Box::new(MockCharSampler::new()); - - anim.expect_sample().return_const(3.0); - - let sampler = ComposedSampler::new(anim, fill, color, char); - - assert!(matches!(sampler.sample(0.7, Vector::new(0.3, 0.1)), Sample::Keep)); - } - - #[test] - fn sample_draw() { - let mut anim = Box::new(MockAnimation::new()); - let mut fill = Box::new(MockFillMode::new()); - let mut color = Box::new(MockColorSampler::new()); - let mut char = Box::new(MockCharSampler::new()); - - anim.expect_sample().once().with(eq(0.2), always()).return_const(0.3); - fill.expect_sample().once().with(eq(0.3), always()).return_const(0.8); - color.expect_sample().once().with(eq(0.8)).return_const(Color::Blue); - char.expect_sample().once().with(eq(0.3)).return_const('Z'); - - let sampler = ComposedSampler::new(anim, fill, color, char); - - assert!(matches!(sampler.sample(0.2, Vector::new(0.3, 0.1)), Sample::Draw { char: 'Z', color: Color::Blue })); - } - - #[test] - fn sample_clear() { - let mut anim = Box::new(MockAnimation::new()); - let fill = Box::new(MockFillMode::new()); - let color = Box::new(MockColorSampler::new()); - let char = Box::new(MockCharSampler::new()); - - anim.expect_sample().return_const(-0.4); - - let sampler = ComposedSampler::new(anim, fill, color, char); - - assert!(matches!(sampler.sample(0.7, Vector::new(0.3, 0.1)), Sample::Clear)); - } - - #[test] - fn sample_almost_draw() { - let mut anim = Box::new(MockAnimation::new()); - let fill = Box::new(MockFillMode::new()); - let color = Box::new(MockColorSampler::new()); - let char = Box::new(MockCharSampler::new()); - - anim.expect_sample().return_const(1.0); - - let sampler = ComposedSampler::new(anim, fill, color, char); - - assert!(matches!(sampler.sample(0.7, Vector::new(0.3, 0.1)), Sample::Keep)); - } - - - #[test] - fn sample_almost_clear() { - let mut anim = Box::new(MockAnimation::new()); - let mut fill = Box::new(MockFillMode::new()); - let mut color = Box::new(MockColorSampler::new()); - let mut char = Box::new(MockCharSampler::new()); - - anim.expect_sample().return_const(0.0); - fill.expect_sample().return_const(0.8); - color.expect_sample().return_const(Color::Blue); - char.expect_sample().return_const('a'); - - let sampler = ComposedSampler::new(anim, fill, color, char); - - assert!(matches!(sampler.sample(0.7, Vector::new(0.3, 0.1)), Sample::Draw { .. })); - } -} \ No newline at end of file diff --git a/src/surface.rs b/src/surface.rs deleted file mode 100644 index 5311eb2..0000000 --- a/src/surface.rs +++ /dev/null @@ -1,214 +0,0 @@ -use anyhow::Error; -use crossterm::cursor::{Hide, MoveTo, Show}; -use crossterm::{ExecutableCommand, QueueableCommand}; -use crossterm::style::{Color, Print, SetForegroundColor}; -use crossterm::terminal::{Clear, ClearType}; -use std::io::Write; -use crate::array::Array2D; - -#[cfg(test)] -use mockall::automock; - -/// A surface to draw characters on. -#[cfg_attr(test, automock)] -pub trait Surface { - fn width(&self) -> usize; - fn height(&self) -> usize; - - /// Overwrite the character on screen with this value. - fn draw(&mut self, x: usize, y: usize, char: char, color: Color); - - /// Clear the character on screen. - fn clear(&mut self, x: usize, y: usize); - - /// Present the finished frame. - fn present(&mut self) -> Result<(), Error>; -} - -/// Renders the frames into a [Write] struct. -pub struct WriteSurface { - out: T, - array: Array2D, -} - -#[derive(Copy, Clone)] -enum Cell { - Keep, - Draw { char: char, color: Color }, -} - -impl Default for Cell { - fn default() -> Self { Cell::Keep } -} - -impl WriteSurface { - pub fn new(mut out: T, width: usize, height: usize) -> Result { - out.queue(Hide)?; - - Ok(Self { - out, - array: Array2D::new(width, height) - }) - } - - fn try_drop(&mut self) -> Result<(), Error> { - self.out.queue(Show)?; - self.out.execute(Clear(ClearType::Purge))?; - Ok(()) - } -} - -impl Surface for WriteSurface { - fn width(&self) -> usize { - self.array.width() - } - - fn height(&self) -> usize { - self.array.height() - } - - fn draw(&mut self, x: usize, y: usize, char: char, color: Color) { - self.array[(x, y)] = Cell::Draw { char, color }; - } - - fn clear(&mut self, x: usize, y: usize) { - self.array[(x, y)] = Cell::Draw { char: ' ', color: Color::Reset }; - } - - fn present(&mut self) -> Result<(), Error> { - let mut needs_move; - let mut last_color = None; - - for y in 0..self.array.height() { - needs_move = true; - - for x in 0..self.array.width() { - match self.array[(x, y)] { - Cell::Keep => { - needs_move = true; - } - Cell::Draw { char, color } => { - if needs_move { - needs_move = false; - self.out.queue(MoveTo(x as u16, y as u16))?; - } - if last_color.is_none() || last_color.unwrap() != color { - last_color = Some(color); - self.out.queue(SetForegroundColor(color))?; - } - self.out.queue(Print(char))?; - } - } - } - } - self.out.flush()?; - Ok(()) - } -} - -impl Drop for WriteSurface { - fn drop(&mut self) { - if let Err(e) = self.try_drop() { - println!("{}", e); - } - } -} - -#[cfg(test)] -mod test { - use std::cell::RefCell; - use std::rc::Rc; - use super::*; - - #[derive(PartialEq, Debug)] - struct Data { - flushed: Vec>, - buffer: Vec - } - - struct MockWrite { - data: Rc> - } - - impl Data { - fn new() -> Rc> { - Rc::new(RefCell::new(Self { - flushed: Vec::new(), - buffer: Vec::new() - })) - } - } - - impl MockWrite { - fn new(data: Rc>) -> Box { - Box::new(Self { data }) - } - } - - impl Write for MockWrite { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - self.data.borrow_mut().buffer.extend_from_slice(buf); - Ok(buf.len()) - } - - fn flush(&mut self) -> std::io::Result<()> { - let data = self.data.borrow_mut().buffer.drain(..).collect(); - - self.data.borrow_mut().flushed.push(data); - Ok(()) - } - } - - #[test] - fn width() { - let data = Data::new(); - let mock = MockWrite::new(data); - let surface = WriteSurface::new(mock, 10, 2).unwrap(); - - assert_eq!(10, surface.width()); - } - - #[test] - fn height() { - let data = Data::new(); - let mock = MockWrite::new(data); - let surface = WriteSurface::new(mock, 5, 8).unwrap(); - - assert_eq!(8, surface.height()); - } - - #[test] - fn present() { - // Execute - let data = Data::new(); - let mock = MockWrite::new(data.clone()); - let mut surface = WriteSurface::new(mock, 3, 2).unwrap(); - - surface.draw(0, 0, 'A', Color::Green); - surface.draw(1, 0, 'x', Color::Green); - surface.clear(1, 1); - surface.present().unwrap(); - - drop(surface); - - // Recreate expectation - let expected = Data::new(); - let mut stream = MockWrite::new(expected.clone()); - - stream.queue(Hide).unwrap(); - stream.queue(MoveTo(0, 0)).unwrap(); - stream.queue(SetForegroundColor(Color::Green)).unwrap(); - stream.queue(Print('A')).unwrap(); - stream.queue(Print('x')).unwrap(); - stream.queue(MoveTo(1, 1)).unwrap(); - stream.queue(SetForegroundColor(Color::Reset)).unwrap(); - stream.queue(Print(' ')).unwrap(); - stream.flush().unwrap(); - stream.queue(Show).unwrap(); - stream.queue(Clear(ClearType::Purge)).unwrap(); - stream.flush().unwrap(); - - // Compare - assert_eq!(expected, data); - } -} \ No newline at end of file diff --git a/src/timer.rs b/src/timer.rs deleted file mode 100644 index fecf037..0000000 --- a/src/timer.rs +++ /dev/null @@ -1,55 +0,0 @@ -use std::thread::sleep; -use std::time::{Duration, Instant}; - -#[cfg(test)] -use mockall::automock; - -/// Allows for periodic execution of code. -#[cfg_attr(test, automock)] -pub trait Timer { - /// Set the start time of the timer. - fn set(&mut self); - - /// Get the elapsed time since calling [Timer::set]. - fn elapsed(&self) -> Duration; - - /// Sleep until the next tick starts. - fn sleep(&mut self); -} - -/// A simple [Timer] based on the system clock. -pub struct SimpleTimer { - delay: Duration, - start: Instant, - last: Instant -} - -impl SimpleTimer { - pub fn new(delay: Duration) -> Self { - Self { - delay, - start: Instant::now(), - last: Instant::now(), - } - } -} - -impl Timer for SimpleTimer { - fn set(&mut self) { - self.start = Instant::now(); - self.last = self.start; - } - - fn elapsed(&self) -> Duration { - Instant::now() - self.start - } - - fn sleep(&mut self) { - let now = Instant::now(); - - if self.last + self.delay > now { - sleep(self.delay - (now - self.last)); - } - self.last = Instant::now(); - } -} \ No newline at end of file diff --git a/src/vec.rs b/src/vec.rs deleted file mode 100644 index 040eeef..0000000 --- a/src/vec.rs +++ /dev/null @@ -1,119 +0,0 @@ -use std::ops::Sub; - -/// A vector with a x and y axis. -#[derive(Copy, Clone)] -pub struct Vector { - pub x: f32, - pub y: f32 -} - -impl Vector { - pub fn new(x: f32, y: f32) -> Self { - Self { x, y } - } - - /// Returns the halfway point. - pub fn center(self) -> Self { - Self::new(self.x / 2.0, self.y / 2.0) - } - - /// Returns the length. - pub fn length(self) -> f32 { - (self.x * self.x + self.y * self.y).sqrt() - } - - /// Returns the angle. - pub fn angle(self) -> f32 { - self.y.atan2(self.x) - } - - /// Returns the value of the smaller axis. - pub fn smaller(self) -> f32 { - self.x.min(self.y) - } - - /// Converts all axis into positive values. - pub fn abs(self) -> Vector { - Self::new(self.x.abs(), self.y.abs()) - } - - /// Returns the sum of all axis. - pub fn sum(self) -> f32 { - self.x + self.y - } - - /// Creates a vector with the on screen coordinates based on the terminal coordinates. - /// # Arguments - /// * `x`: The x axis of the terminal character. - /// * `y`: The y axis of the terminal character. - pub fn from_terminal(x: usize, y: usize) -> Self { - Self::new(x as f32, y as f32 * 2.0) - } -} - -impl Sub for Vector { - type Output = Vector; - - fn sub(self, rhs: Self) -> Self::Output { - Vector::new(self.x - rhs.x, self.y - rhs.y) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn new() { - let vec = Vector::new(3.0, 5.0); - - assert_eq!(3.0, vec.x); - assert_eq!(5.0, vec.y); - } - - #[test] - fn center() { - let vec = Vector::new(3.0, 8.0); - - assert_eq!(1.5, vec.center().x); - assert_eq!(4.0, vec.center().y); - } - - #[test] - fn length() { - let vec = Vector::new(3.0, 6.0); - - assert!(6.7 < vec.length() && vec.length() < 6.8); - } - - #[test] - fn angle() { - let vec = Vector::new(3.0, 6.0); - - assert!(1.1 < vec.angle() && vec.angle() < 1.2); - } - - #[test] - fn smaller() { - assert_eq!(4.0, Vector::new(7.0, 4.0).smaller()); - assert_eq!(2.0, Vector::new(2.0, 9.0).smaller()); - } - - #[test] - fn from_terminal() { - let vec = Vector::from_terminal(2, 4); - - assert_eq!(2.0, vec.x); - assert_eq!(8.0, vec.y); - } - - #[test] - fn sub() { - let left = Vector::new(8.0, 15.0); - let right = Vector::new(2.0, 4.0); - let result = left - right; - - assert_eq!(6.0, result.x); - assert_eq!(11.0, result.y); - } -} \ No newline at end of file