From 4a0e7b5e71adbca33d9beeb5c961168447b813cd Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Sat, 22 Feb 2020 21:23:28 +0100 Subject: [PATCH] initial commit --- .gitignore | 5 + Cargo.lock | 1637 +++++++++++++++++ Cargo.toml | 33 + LICENSE | 21 + README.md | 2 + src/display/mod.rs | 5 + src/display/rectangle_grid.rs | 322 ++++ src/display/state.rs | 396 ++++ src/filesystem/mod.rs | 3 + src/filesystem/scan_folder.rs | 54 + src/main.rs | 154 ++ src/rectangle_grid.rs | 322 ++++ src/tests/cases/mod.rs | 2 + .../cases/snapshots/ui__eleven_files.snap | 55 + .../ui__two_large_files_one_small_file.snap | 55 + src/tests/cases/test_utils.rs | 32 + src/tests/cases/ui.rs | 130 ++ src/tests/fakes/fake_input.rs | 28 + src/tests/fakes/fake_output.rs | 115 ++ src/tests/fakes/mod.rs | 5 + src/tests/mod.rs | 2 + src/util/event.rs | 83 + src/util/mod.rs | 77 + 23 files changed, 3538 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 src/display/mod.rs create mode 100644 src/display/rectangle_grid.rs create mode 100644 src/display/state.rs create mode 100644 src/filesystem/mod.rs create mode 100644 src/filesystem/scan_folder.rs create mode 100644 src/main.rs create mode 100644 src/rectangle_grid.rs create mode 100644 src/tests/cases/mod.rs create mode 100644 src/tests/cases/snapshots/ui__eleven_files.snap create mode 100644 src/tests/cases/snapshots/ui__two_large_files_one_small_file.snap create mode 100644 src/tests/cases/test_utils.rs create mode 100644 src/tests/cases/ui.rs create mode 100644 src/tests/fakes/fake_input.rs create mode 100644 src/tests/fakes/fake_output.rs create mode 100644 src/tests/fakes/mod.rs create mode 100644 src/tests/mod.rs create mode 100644 src/util/event.rs create mode 100644 src/util/mod.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..51c125b --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.cargo/ +target/ +vendor/ +vendor.tar +**/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..3457749 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1637 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "async-std" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "async-task 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-timer 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "kv-log-macro 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", + "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "async-task" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "backtrace" +version = "0.3.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "c2-chacha" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cargo-insta" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", + "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cassowary" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cc" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "chrono" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "clicolors-control" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "console" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "console" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "console" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-channel" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-queue" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "difference" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "dtoa" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "either" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "failure" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-channel 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-executor 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-channel" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-core" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-executor" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-io" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-macro" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-sink" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-task" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-timer" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-util" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-channel 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-macro 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-nested 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "generic-array" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "getrandom" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glob" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hermit-abi" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "insta" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "console 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pest 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "insta" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "console 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itertools" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "jwalk" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kv-log-macro" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.65" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "linked-hash-map" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lock_api" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memoffset" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mio" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mio-uds" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miow" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "net2" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-integer" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num_cpus" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "numtoa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "once_cell" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "parking_lot" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pest" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pest_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pest 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "pest_generator 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pest_generator" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pest 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "pest_meta 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pest_meta" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "pest 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pin-project-lite" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pin-utils" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ppv-lite86" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro-hack" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro-nested" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon-core" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc-demangle" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scopeguard" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_yaml" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sha-1" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "smallvec" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "stderrlog" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "structopt" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "structopt-derive" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synstructure" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termcolor" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termion" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termios" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "time" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tui" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cassowary 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "typenum" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ucd-trie" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-segmentation" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-width" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "uuid" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "uuid" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "visual-size-ls" +version = "0.6.2" +dependencies = [ + "async-std 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo-insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cassowary 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "jwalk 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "stderrlog 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tui 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "walkdir" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasi" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wincolor" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "yaml-rust" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "743ad5a418686aad3b87fd14c43badd828cf26e214a00f92a384291cf22e1811" +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum async-std 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0bf6039b315300e057d198b9d3ab92ee029e31c759b7f1afae538145e6f18a3e" +"checksum async-task 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d22dc86693d375d2733b536fd8914bea0fa93adf4b1e6bcbd9c7c500cb62d920" +"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" +"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" +"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" +"checksum cargo-insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e22a28c661f0fb0474ef90d63b4bc834bf2c179550608783594f358f5ac74cc2" +"checksum cassowary 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" +"checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" +"checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ca57c2c14b8a2bf3105bc9d15574aad80babf6a9c44b1058034cdf8bd169628" +"checksum console 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b147390a412132d75d10dd3b7b175a69cf5fd95032f7503c7091b8831ba10242" +"checksum console 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "45e0f3986890b3acbc782009e2629dfe2baa430ac091519ce3be26164a2ae6c0" +"checksum crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" +"checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c" +"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca" +"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac" +"checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" +"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" +"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" +"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +"checksum dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3" +"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +"checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" +"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" +"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +"checksum futures 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ad6636318d07abeb4656157ef1936c64485f066c7f9ce5d7c5b879fcb6dd5ccb" +"checksum futures-channel 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7264eb65b194d2fa6ec31b898ead7c332854bfa42521659226e72a585fca5b85" +"checksum futures-core 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b597b16aa1a19ce2dfde5128a7c656d75346b35601a640be2d9efd4e9c83609d" +"checksum futures-executor 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "46a5e593d77bee52393c7f3b16b8b413214096d3f7dc4f5f4c57dee01ad2bdaf" +"checksum futures-io 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3d429f824b5e5dbd45fc8e54e1005a37e1f8c6d570cd64d0b59b24d3a80b8b8e" +"checksum futures-macro 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d75b72904b78044e0091355fc49d29f48bff07a68a719a41cf059711e071b4" +"checksum futures-sink 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "04299e123547ea7c56f3e1b376703142f5fc0b6700433eed549e9d0b8a75a66c" +"checksum futures-task 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "86f9ceab4bce46555ee608b1ec7c414d6b2e76e196ef46fa5a8d4815a8571398" +"checksum futures-timer 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a1de7508b218029b0f01662ed8f61b1c964b3ae99d6f25462d0f55a595109df6" +"checksum futures-util 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7d2f1296f7644d2cd908ebb2fa74645608e39f117c72bac251d40418c6d74c4f" +"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" +"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" +"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" +"checksum insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23f83ab4ee86f38b292f0420c27fd412690a4baa9ea0ad4e3fa624bf34379b76" +"checksum insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d499dc062e841590a67230d853bce62d0abeb91304927871670b7c55c461349" +"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +"checksum itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "87fa75c9dea7b07be3138c49abbb83fd4bea199b5cdc76f9804458edc5da0d6e" +"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" +"checksum jwalk 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b49158e8bc659d622d57bf8d9739881409956f3e617cb6bd3c0770ef767ed7a8" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum kv-log-macro 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c54d9f465d530a752e6ebdc217e081a7a614b48cb200f6f0aee21ba6bc9aabb" +"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" +"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" +"checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" +"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" +"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223" +"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" +"checksum mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" +"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" +"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" +"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" +"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" +"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" +"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" +"checksum once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b" +"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +"checksum parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" +"checksum parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" +"checksum pest 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e4fb201c5c22a55d8b24fef95f78be52738e5e1361129be1b5e862ecdb6894a" +"checksum pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +"checksum pest_generator 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9fcf299b5712d06ee128a556c94709aaa04512c4dffb8ead07c5c998447fc0" +"checksum pest_meta 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "df43fd99896fd72c485fe47542c7b500e4ac1e8700bf995544d1317a60ded547" +"checksum pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "237844750cfbb86f67afe27eee600dfbbcb6188d734139b534cbfbf4f96792ae" +"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" +"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +"checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" +"checksum proc-macro-nested 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "369a6ed065f249a159e06c45752c780bda2fb53c995718f9e484d08daa9eb42e" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" +"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +"checksum rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098" +"checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +"checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" +"checksum regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b28dfe3fe9badec5dbf0a79a9cccad2cfc2ab5484bdb3e44cbd1ae8b3ba2be06" +"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" +"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" +"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" +"checksum serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25" +"checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" +"checksum sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +"checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" +"checksum stderrlog 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "32e5ee9b90a5452c570a0b0ac1c99ae9498db7e56e33d74366de7f2a7add7f25" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +"checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" +"checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" +"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +"checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92" +"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" +"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" +"checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330" +"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" +"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum tui 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ff64c925f5e20d7a393c598a33b6afc9c9942e7ebc530085588f5b7667ea559" +"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" +"checksum ucd-trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8f00ed7be0c1ff1e24f46c3d2af4859f7e863672ba3a6e92e7cff702bf9f06c2" +"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" +"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" +"checksum uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" +"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" +"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" +"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a9b9aab --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "visual-size-ls" +version = "0.6.2" +authors = ["Aram Drevekenin "] +description = """ +""" +license = "MIT" +edition = "2018" + +[dependencies] +tui = "0.5" +bitflags = "1.0" +cassowary = "0.3" +itertools = "0.8" +log = "0.4" +either = "1.5" +unicode-segmentation = "1.2" +unicode-width = "0.1" +termion = "1.5" +failure = "0.1" +async-std = "*" +futures = "*" +walkdir = "2" +jwalk = "0.3" + +[dev-dependencies] +stderrlog = "0.4" +rand = "0.6" +failure = "0.1" +structopt = "0.2" +insta = "0.12.0" +cargo-insta = "0.11.0" +uuid = { version = "0.8", features = ["v4"] } diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..235927f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020 Aram Drevekenin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f884d21 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# visual-size-ls +wip diff --git a/src/display/mod.rs b/src/display/mod.rs new file mode 100644 index 0000000..db6f098 --- /dev/null +++ b/src/display/mod.rs @@ -0,0 +1,5 @@ +pub mod rectangle_grid; +pub mod state; + +pub use state::*; +pub use rectangle_grid::*; diff --git a/src/display/rectangle_grid.rs b/src/display/rectangle_grid.rs new file mode 100644 index 0000000..c035d33 --- /dev/null +++ b/src/display/rectangle_grid.rs @@ -0,0 +1,322 @@ +use tui::buffer::Buffer; +use tui::layout::Rect; +use tui::style::{Style, Color}; +use tui::symbols::line; +use tui::widgets::{Borders, Widget}; + +#[derive(Clone, Debug)] +pub struct RectWithText { + pub rect: Rect, + pub text: String, + pub selected: bool, +} + +#[derive(Clone)] +pub struct RectangleGrid { + rectangles: Vec +} + +// impl<'a> Default for RectangleGrid<'a> { +// fn default() -> RectangleGrid<'a> { +// RectangleGrid { +// title: None, +// title_style: Default::default(), +// borders: Borders::NONE, +// border_style: Default::default(), +// style: Default::default(), +// } +// } +// } + +pub struct BoundariesToUse { + pub TOP_RIGHT: String, + pub VERTICAL: String, + pub HORIZONTAL: String, + pub TOP_LEFT: String, + pub BOTTOM_RIGHT: String, + pub BOTTOM_LEFT: String, + pub VERTICAL_LEFT: String, + pub VERTICAL_RIGHT: String, + pub HORIZONTAL_DOWN: String, + pub HORIZONTAL_UP: String, + pub CROSS: String, +} + +pub mod boundaries { + pub const TOP_RIGHT: &str = "┐"; + pub const VERTICAL: &str = "│"; + pub const HORIZONTAL: &str = "─"; + pub const TOP_LEFT: &str = "┌"; + pub const BOTTOM_RIGHT: &str = "┘"; + pub const BOTTOM_LEFT: &str = "└"; + pub const VERTICAL_LEFT: &str = "┤"; + pub const VERTICAL_RIGHT: &str = "├"; + pub const HORIZONTAL_DOWN: &str = "┬"; + pub const HORIZONTAL_UP: &str = "┴"; + pub const CROSS: &str = "┼"; +} + + +pub mod selected_boundaries { + pub const TOP_RIGHT: &str = "╗"; + pub const VERTICAL: &str = "║"; + pub const HORIZONTAL: &str = "═"; + pub const TOP_LEFT: &str = "╔"; + pub const BOTTOM_RIGHT: &str = "╝"; + pub const BOTTOM_LEFT: &str = "╚"; + pub const VERTICAL_LEFT: &str = "╣"; + pub const VERTICAL_RIGHT: &str = "╠"; + pub const HORIZONTAL_DOWN: &str = "╦"; + pub const HORIZONTAL_UP: &str = "╩"; + pub const CROSS: &str = "╬"; +} + +impl<'a> RectangleGrid { + pub fn new (rectangles: Vec) -> Self { + RectangleGrid { rectangles } + } +} + +fn truncate_middle(row: &str, max_length: u16) -> String { + if max_length <= 6 { + String::from(".") // TODO: make sure this never happens +// } else if max_length == 4 { +// String::from("[..]") + } else if row.len() as u16 > max_length { + let first_slice = &row[0..(max_length as usize / 2) - 2]; + let second_slice = &row[(row.len() - (max_length / 2) as usize + 2)..row.len()]; + format!("{}[..]{}", first_slice, second_slice) + } else { + row.to_string() + } +} + +impl<'a> Widget for RectangleGrid { + fn draw(&mut self, area: Rect, buf: &mut Buffer) { + if area.width < 2 || area.height < 2 { + return; + } + for rect_with_text in &self.rectangles { + + let rect_boundary_chars = BoundariesToUse { + TOP_RIGHT: String::from(boundaries::TOP_RIGHT), + VERTICAL: String::from(boundaries::VERTICAL), + HORIZONTAL: String::from(boundaries::HORIZONTAL), + TOP_LEFT: String::from(boundaries::TOP_LEFT), + BOTTOM_RIGHT: String::from(boundaries::BOTTOM_RIGHT), + BOTTOM_LEFT: String::from(boundaries::BOTTOM_LEFT), + VERTICAL_LEFT: String::from(boundaries::VERTICAL_LEFT), + VERTICAL_RIGHT: String::from(boundaries::VERTICAL_RIGHT), + HORIZONTAL_DOWN: String::from(boundaries::HORIZONTAL_DOWN), + HORIZONTAL_UP: String::from(boundaries::HORIZONTAL_UP), + CROSS: String::from(boundaries::CROSS), + }; + let rect = rect_with_text.rect; + let max_text_length = if rect.width > 4 { rect.width - 4 } else { 0 }; + // TODO: we should not accept a rectangle with a width of less than 8 so that the text + // will be at least partly legible... these rectangles should be created with a small + // height instead + let display_text = truncate_middle(&rect_with_text.text, max_text_length); + let text_length = display_text.len(); // TODO: better + + let text_start_position = ((rect.width - text_length as u16) as f64 / 2.0).ceil() as u16 + rect.x; + + + + + let text_style = if rect_with_text.selected { + Style::default().bg(Color::White).fg(Color::Black) + } else { + Style::default() + }; + buf.set_string(text_start_position, rect.height / 2 + rect.y, display_text, text_style); + + for x in rect.x..(rect.x + rect.width + 1) { + if x == rect.x { + let current_symbol_top = &buf.get(x, rect.y).symbol; + if current_symbol_top == &rect_boundary_chars.CROSS || current_symbol_top == &rect_boundary_chars.HORIZONTAL_DOWN { + // no-op + } else if current_symbol_top == &rect_boundary_chars.TOP_RIGHT || current_symbol_top == &rect_boundary_chars.HORIZONTAL { + buf.get_mut(x, rect.y) // TODO: do not get twice? + .set_symbol(&rect_boundary_chars.HORIZONTAL_DOWN); + } else if current_symbol_top == &rect_boundary_chars.BOTTOM_LEFT || current_symbol_top == &rect_boundary_chars.VERTICAL || current_symbol_top == &rect_boundary_chars.VERTICAL_RIGHT { + buf.get_mut(x, rect.y) // TODO: do not get twice? + .set_symbol(&rect_boundary_chars.VERTICAL_RIGHT); + } else if current_symbol_top == &rect_boundary_chars.HORIZONTAL_UP || current_symbol_top == &rect_boundary_chars.BOTTOM_LEFT || current_symbol_top == &rect_boundary_chars.VERTICAL_LEFT { + buf.get_mut(x, rect.y) // TODO: do not get twice? + .set_symbol(&rect_boundary_chars.CROSS); + } else { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.TOP_LEFT); + // .set_style(self.border_style); + } + + let current_symbol_bottom = &buf.get(x, rect.y + rect.height).symbol; + if current_symbol_bottom == &rect_boundary_chars.BOTTOM_RIGHT || current_symbol_bottom == &rect_boundary_chars.HORIZONTAL { + buf.get_mut(x, rect.y + rect.height) + .set_symbol(&rect_boundary_chars.HORIZONTAL_UP); + } else if current_symbol_bottom == &rect_boundary_chars.VERTICAL { + buf.get_mut(x, rect.y + rect.height) + .set_symbol(&rect_boundary_chars.VERTICAL_RIGHT); + } else { + buf.get_mut(x, rect.y + rect.height) + .set_symbol(&rect_boundary_chars.BOTTOM_LEFT); + } + } else if x == rect.x + rect.width { + let current_symbol_top = &buf.get(x, rect.y).symbol; + if current_symbol_top == &rect_boundary_chars.CROSS { + // no-op + } else if current_symbol_top == &rect_boundary_chars.TOP_LEFT || current_symbol_top == &rect_boundary_chars.TOP_RIGHT || current_symbol_top == &rect_boundary_chars.HORIZONTAL { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.HORIZONTAL_DOWN); + } else if current_symbol_top == &rect_boundary_chars.HORIZONTAL_UP { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.CROSS); + } else if current_symbol_top == &rect_boundary_chars.BOTTOM_RIGHT { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.VERTICAL_LEFT); + } else { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.TOP_RIGHT); + } + let current_symbol_bottom = &buf.get(x, rect.y + rect.height).symbol; + if current_symbol_bottom == &rect_boundary_chars.BOTTOM_LEFT || current_symbol_bottom == &rect_boundary_chars.BOTTOM_RIGHT || current_symbol_bottom == &rect_boundary_chars.HORIZONTAL { + buf.get_mut(x, rect.y + rect.height) + .set_symbol(&rect_boundary_chars.HORIZONTAL_UP); + } else { + buf.get_mut(x, rect.y + rect.height) + .set_symbol(&rect_boundary_chars.BOTTOM_RIGHT); + } + } else { + let current_symbol_top = &buf.get(x, rect.y).symbol; + if current_symbol_top == &rect_boundary_chars.CROSS || current_symbol_top == &rect_boundary_chars.HORIZONTAL_UP { + // no-op + } else if current_symbol_top == &rect_boundary_chars.TOP_LEFT || current_symbol_top == &rect_boundary_chars.TOP_RIGHT { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.HORIZONTAL_DOWN); + } else if current_symbol_top == &rect_boundary_chars.BOTTOM_LEFT || current_symbol_top == &rect_boundary_chars.BOTTOM_RIGHT { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.HORIZONTAL_UP); + } else if current_symbol_top == &rect_boundary_chars.VERTICAL { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.CROSS); + } else { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.HORIZONTAL); + } + let current_symbol_bottom = &buf.get(x, rect.y + rect.height).symbol; + if current_symbol_bottom == &rect_boundary_chars.BOTTOM_LEFT || current_symbol_bottom == &rect_boundary_chars.BOTTOM_RIGHT { + buf.get_mut(x, rect.y + rect.height) + .set_symbol(&rect_boundary_chars.HORIZONTAL_UP); + } else if current_symbol_bottom == &rect_boundary_chars.VERTICAL { + buf.get_mut(x, rect.y + rect.height) + .set_symbol(&rect_boundary_chars.CROSS); + } else { + buf.get_mut(x, rect.y + rect.height) + .set_symbol(&rect_boundary_chars.HORIZONTAL); + } + } + } + + // sides + for y in (rect.y + 1)..(rect.y + rect.height) { + let current_symbol_left = &buf.get(rect.x, y).symbol; + if current_symbol_left == &rect_boundary_chars.HORIZONTAL { + buf.get_mut(rect.x, y) + .set_symbol(&rect_boundary_chars.CROSS); + } else { + buf.get_mut(rect.x, y) + .set_symbol(&rect_boundary_chars.VERTICAL); + } + let current_symbol_right = &buf.get(rect.x + rect.width, y).symbol; + if current_symbol_right == &rect_boundary_chars.HORIZONTAL { + buf.get_mut(rect.x + rect.width, y) + .set_symbol(&rect_boundary_chars.CROSS); + } else { + buf.get_mut(rect.x + rect.width, y) + .set_symbol(&rect_boundary_chars.VERTICAL); + } + } + + } + +// self.background(area, buf, self.style.bg); +// +// // Sides +// if self.borders.intersects(Borders::LEFT) { +// for y in area.top()..area.bottom() { +// buf.get_mut(area.left(), y) +// .set_symbol(line::VERTICAL) +// .set_style(self.border_style); +// } +// } +// if self.borders.intersects(Borders::TOP) { +// for x in area.left()..area.right() { +// buf.get_mut(x, area.top()) +// .set_symbol(line::HORIZONTAL) +// .set_style(self.border_style); +// } +// } +// if self.borders.intersects(Borders::RIGHT) { +// let x = area.right() - 1; +// for y in area.top()..area.bottom() { +// buf.get_mut(x, y) +// .set_symbol(line::VERTICAL) +// .set_style(self.border_style); +// } +// } +// if self.borders.intersects(Borders::BOTTOM) { +// let y = area.bottom() - 1; +// for x in area.left()..area.right() { +// buf.get_mut(x, y) +// .set_symbol(line::HORIZONTAL) +// .set_style(self.border_style); +// } +// } +// +// // Corners +// if self.borders.contains(Borders::LEFT | Borders::TOP) { +// buf.get_mut(area.left(), area.top()) +// .set_symbol(line::TOP_LEFT) +// .set_style(self.border_style); +// } +// if self.borders.contains(Borders::RIGHT | Borders::TOP) { +// buf.get_mut(area.right() - 1, area.top()) +// .set_symbol(line::TOP_RIGHT) +// .set_style(self.border_style); +// } +// if self.borders.contains(Borders::LEFT | Borders::BOTTOM) { +// buf.get_mut(area.left(), area.bottom() - 1) +// .set_symbol(line::BOTTOM_LEFT) +// .set_style(self.border_style); +// } +// if self.borders.contains(Borders::RIGHT | Borders::BOTTOM) { +// buf.get_mut(area.right() - 1, area.bottom() - 1) +// .set_symbol(line::BOTTOM_RIGHT) +// .set_style(self.border_style); +// } +// +// if area.width > 2 { +// if let Some(title) = self.title { +// let lx = if self.borders.intersects(Borders::LEFT) { +// 1 +// } else { +// 0 +// }; +// let rx = if self.borders.intersects(Borders::RIGHT) { +// 1 +// } else { +// 0 +// }; +// let width = area.width - lx - rx; +// buf.set_stringn( +// area.left() + lx, +// area.top(), +// title, +// width as usize, +// self.title_style, +// ); +// } +// } + } +} diff --git a/src/display/state.rs b/src/display/state.rs new file mode 100644 index 0000000..5026b12 --- /dev/null +++ b/src/display/state.rs @@ -0,0 +1,396 @@ +use tui::layout::Rect; + +use std::collections::HashMap; +use crate::display::rectangle_grid::RectWithText; +use ::std::fmt; + +pub struct DisplaySize(pub f64); + +impl fmt::Display for DisplaySize{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.0 > 999_999_999.0 { + write!(f, "{:.1}G", self.0 / 1_000_000_000.0) + } else if self.0 > 999_999.0 { + write!(f, "{:.1}M", self.0 / 1_000_000.0) + } else if self.0 > 999.0 { + write!(f, "{:.1}K", self.0 / 1000.0) + } else { + write!(f, "{}", self.0) + } + } +} + +#[derive(Debug, Clone)] +pub struct FilePercentage { + pub file_name: String, + pub percentage: f64, +} + +const minimum_height: u16 = 2; // TODO: consts +const minimum_width: u16 = 2; +const height_width_ratio: f64 = 2.5; + +pub struct State { + pub tiles: Vec, + pub file_percentages: Vec, +} + +impl State { + pub fn new() -> Self { + Self { + tiles: Vec::new(), + file_percentages: Vec::new(), + } + } + pub fn set_file_percentages (&mut self, file_percentages: Vec) { + self.file_percentages = file_percentages; + } + pub fn set_tiles(&mut self, full_screen: Rect) { + let total_space_area = full_screen.width as f64 * full_screen.height as f64; + let mut free_spaces = vec![full_screen]; + let mut rectangles_to_render = vec![]; + + let mut has_selected = false; + let currently_selected = self.tiles.iter().find(|&t| t.selected == true); + for file_percentage in &self.file_percentages { + + let total_file_area = total_space_area * file_percentage.percentage; + let file_square_side_width = full_screen.width as f64 * (file_percentage.percentage * 2.0); + let file_square_side_height = total_file_area / file_square_side_width; + + let mut candidate_index = 0; + loop { + if candidate_index >= free_spaces.len() { + break; + } + if let Some(candidate) = free_spaces.get(candidate_index) { + let mut file_rect = None; + if candidate.width >= file_square_side_width as u16 && + candidate.height >= file_square_side_height as u16 + { + file_rect = Some(RectWithText { + rect: Rect { + x: candidate.x, + y: candidate.y, + width: file_square_side_width as u16, + height: file_square_side_height as u16, + }, + text: file_percentage.file_name.clone(), + selected: false, + }); + } else if candidate.height >= file_square_side_height as u16 && + candidate.width >= (total_file_area / candidate.height as f64) as u16 + { + let height = candidate.height; + let width = (total_file_area / height as f64) as u16; + file_rect = Some(RectWithText { + rect: Rect { + x: candidate.x, + y: candidate.y, + width, + height, + }, + text: file_percentage.file_name.clone(), + selected: false, + }); + } else if candidate.width >= file_square_side_width as u16 && + candidate.height >= (total_file_area / candidate.width as f64) as u16 + { + let width = candidate.width; + let height = (total_file_area / width as f64) as u16; + file_rect = Some(RectWithText { + rect: Rect { + x: candidate.x, + y: candidate.y, + width, + height, + }, + text: file_percentage.file_name.clone(), + selected: false, + }); + } else if candidate.height >= minimum_height && + candidate.width >= ((total_file_area as u16 / minimum_height) as f64 * height_width_ratio) as u16 + { + file_rect = Some(RectWithText { + rect: Rect { + x: candidate.x, + y: candidate.y, + width: ((total_file_area as u16 / minimum_height) as f64 * height_width_ratio) as u16, + height: minimum_height, + }, + text: file_percentage.file_name.clone(), + selected: false, + }); + } else if candidate.width >= minimum_width && + candidate.height >= ((total_file_area as u16 / minimum_width) as f64 / height_width_ratio) as u16 + { + file_rect = Some(RectWithText { + rect: Rect { + x: candidate.x, + y: candidate.y, + width: minimum_width, + height: ((total_file_area as u16 / minimum_width) as f64 / height_width_ratio) as u16, + }, + text: file_percentage.file_name.clone(), + selected: false, + }); + } else { + } + if let Some(mut rect_with_text) = file_rect { + // TODO: insert these at index? + if rect_with_text.rect.width > 1 && rect_with_text.rect.height > 1 { + let new_rectangle_right = Rect { + x: candidate.x + rect_with_text.rect.width, + width: (candidate.width as i16 - rect_with_text.rect.width as i16).abs() as u16, + y: candidate.y, + height: rect_with_text.rect.height + }; + let mut new_rectangle_bottom = Rect { + x: candidate.x, + width: candidate.width, + y: candidate.y + rect_with_text.rect.height, + height: (candidate.height as i16 - rect_with_text.rect.height as i16).abs() as u16, + }; + free_spaces.remove(candidate_index); // TODO: better - read api + if new_rectangle_right.width > 1 && new_rectangle_right.height > 1 && new_rectangle_right.x + new_rectangle_right.width <= full_screen.width { + let free_rect_above_new = free_spaces.iter_mut() + .find(|rect| rect.y + rect.height == new_rectangle_right.y && rect.x == new_rectangle_right.x && rect.x + rect.width == new_rectangle_right.x + new_rectangle_right.width); + + match free_rect_above_new { + Some(free_rect_above_new) => { + free_rect_above_new.height += new_rectangle_right.height; + }, + None => { + free_spaces.push(new_rectangle_right); + } + } + } else if new_rectangle_right.width == 1 { + rect_with_text.rect.width += 1; + } + if new_rectangle_bottom.width > 1 && new_rectangle_bottom.height > 1 && new_rectangle_bottom.y + new_rectangle_bottom.height <= full_screen.height { + free_spaces.push(new_rectangle_bottom); + } else if new_rectangle_bottom.height == 1 { + rect_with_text.rect.height += 1; + new_rectangle_bottom.x = rect_with_text.rect.x + rect_with_text.rect.width; + new_rectangle_bottom.width -= rect_with_text.rect.width; + + let free_rect_above_new = free_spaces.iter_mut() + .find(|rect| rect.y + rect.height == new_rectangle_bottom.y && rect.x == new_rectangle_bottom.x && rect.x + rect.width == new_rectangle_bottom.x + new_rectangle_bottom.width); + + match free_rect_above_new { + Some(free_rect_above_new) => { + free_rect_above_new.height += new_rectangle_bottom.height; + }, + None => { + if new_rectangle_bottom.width > 1 && new_rectangle_bottom.height > 1 && new_rectangle_bottom.y + new_rectangle_bottom.height <= full_screen.height { + free_spaces.push(new_rectangle_bottom); + } else { + // TODO: ??? + } + } + } + + } + match currently_selected { + Some(currently_selected_rect) => { + if currently_selected_rect.text == rect_with_text.text { + rect_with_text.selected = true; + rectangles_to_render.push(rect_with_text); + } else { + rect_with_text.selected = false; + rectangles_to_render.push(rect_with_text); + } + }, + None => { + if has_selected { + rect_with_text.selected = false; + rectangles_to_render.push(rect_with_text); + } else { + has_selected = true; + rect_with_text.selected = true; + rectangles_to_render.push(rect_with_text); + } + } + }; + break; + } else { + candidate_index += 1; + // println!("\rnot bigger than 1!!!111!!111 {:?}", rect_with_text); + } + } else { + candidate_index += 1; + } + } + } + } + for free_rect in free_spaces { + // rounding errors - TODO: find a better way to do this + // TODO: throw if larger than 2 + let occupied_rect_left = rectangles_to_render.iter_mut() + .find(|rect_to_render| { + let occupied_rect = rect_to_render.rect; + occupied_rect.y == free_rect.y && occupied_rect.x + occupied_rect.width == free_rect.x + }); + match occupied_rect_left { + Some(occupied_rect_left) => { + occupied_rect_left.rect.width += free_rect.width + }, + None => { + // TODO: ?? throw? + } + } + + } + self.tiles = rectangles_to_render + } + pub fn clone_currently_selected(&self) -> RectWithText { + self.tiles.iter().find(|t| t.selected == true).expect("could not find selected rect").clone() + } + pub fn move_selected_right (&mut self) { + let currently_selected = self.clone_currently_selected(); + let next_to_the_right = { + let found_next = self.tiles.iter().find(|t| { // TODO: find the rectangle with the most overlap, not just the first + t.rect.x == currently_selected.rect.x + currently_selected.rect.width && + ( + t.rect.y >= currently_selected.rect.y && t.rect.y < currently_selected.rect.y + currently_selected.rect.height || + t.rect.y + t.rect.height >= currently_selected.rect.y && t.rect.y + t.rect.height < currently_selected.rect.y + currently_selected.rect.height || + t.rect.y <= currently_selected.rect.y && t.rect.y + t.rect.height >= currently_selected.rect.y + ) + }); + match found_next { + Some(rect) => Some(rect.clone()), + None => None + } + }; + match next_to_the_right { + Some(rect) => { + for tile in self.tiles.iter_mut() { + if tile.text == rect.text { + tile.selected = true; + } else if tile.text == currently_selected.text { + tile.selected = false; + } + } + }, + None => {} + } + } + pub fn move_selected_left(&mut self) { + let currently_selected = self.clone_currently_selected(); + let next_to_the_left = { + let found_next = self.tiles.iter().find(|t| { // TODO: find the rectangle with the most overlap, not just the first + t.rect.x + t.rect.width == currently_selected.rect.x && + ( + t.rect.y >= currently_selected.rect.y && t.rect.y < currently_selected.rect.y + currently_selected.rect.height || + t.rect.y + t.rect.height >= currently_selected.rect.y && t.rect.y + t.rect.height < currently_selected.rect.y + currently_selected.rect.height || + t.rect.y <= currently_selected.rect.y && t.rect.y + t.rect.height >= currently_selected.rect.y + ) + }); + match found_next { + Some(rect) => Some(rect.clone()), + None => None + } + }; + match next_to_the_left { + Some(rect) => { + for tile in self.tiles.iter_mut() { + if tile.text == rect.text { + tile.selected = true; + } else if tile.text == currently_selected.text { + tile.selected = false; + } + } + }, + None => {} + } + } + pub fn move_selected_down(&mut self) { + let currently_selected = self.clone_currently_selected(); + let next_down = { + let found_next = self.tiles.iter().find(|t| { // TODO: find the rectangle with the most overlap, not just the first + t.rect.y == currently_selected.rect.y + currently_selected.rect.height && + ( + t.rect.x >= currently_selected.rect.x && t.rect.x < currently_selected.rect.x + currently_selected.rect.width || + t.rect.x + t.rect.width >= currently_selected.rect.x && t.rect.x + t.rect.width < currently_selected.rect.x + currently_selected.rect.width || + t.rect.x <= currently_selected.rect.x && t.rect.x + t.rect.width >= currently_selected.rect.x + ) + }); + match found_next { + Some(rect) => Some(rect.clone()), + None => None + } + }; + match next_down { + Some(rect) => { + for tile in self.tiles.iter_mut() { + if tile.text == rect.text { + tile.selected = true; + } else if tile.text == currently_selected.text { + tile.selected = false; + } + } + }, + None => {} + } + } + pub fn move_selected_up(&mut self) { + let currently_selected = self.clone_currently_selected(); + let next_up = { + let found_next = self.tiles.iter().find(|t| { // TODO: find the rectangle with the most overlap, not just the first + t.rect.y + t.rect.height == currently_selected.rect.y && + ( + t.rect.x >= currently_selected.rect.x && t.rect.x < currently_selected.rect.x + currently_selected.rect.width || + t.rect.x + t.rect.width >= currently_selected.rect.x && t.rect.x + t.rect.width < currently_selected.rect.x + currently_selected.rect.width || + t.rect.x <= currently_selected.rect.x && t.rect.x + t.rect.width >= currently_selected.rect.x + ) + }); + match found_next { + Some(rect) => Some(rect.clone()), + None => None + } + }; + match next_up { + Some(rect) => { + for tile in self.tiles.iter_mut() { + if tile.text == rect.text { + tile.selected = true; + } else if tile.text == currently_selected.text { + tile.selected = false; + } + } + }, + None => {} + } + } +} + +pub fn calculate_percentages (file_sizes: HashMap) -> Vec { + let mut file_percentages = Vec::new(); + let total_size = file_sizes.values().fold(0, |acc, size| acc + size); + let mut small_files = FilePercentage { + file_name: String::from("Small files"), + percentage: 0.0, + }; + for (path, size) in file_sizes.iter() { + let percentage = *size as f64 / total_size as f64; + let file_percentage = FilePercentage { + file_name: format!("{} {} ({:.0}%)", path, DisplaySize(*size as f64),percentage * 100.0), + percentage, + }; + if file_percentage.percentage <= 0.01 { // TODO: calculate this and not hard-coded + small_files.percentage += file_percentage.percentage; + } else { + file_percentages.push(file_percentage); + } + } + small_files.file_name = format!("Small files ({:.0}%)", small_files.percentage * 100.0); + file_percentages.push(small_files); + file_percentages.sort_by(|a, b| { + if a.percentage == b.percentage { + a.file_name.partial_cmp(&b.file_name).unwrap() + } else { + b.percentage.partial_cmp(&a.percentage).unwrap() + } + }); + file_percentages +} diff --git a/src/filesystem/mod.rs b/src/filesystem/mod.rs new file mode 100644 index 0000000..ec21517 --- /dev/null +++ b/src/filesystem/mod.rs @@ -0,0 +1,3 @@ +mod scan_folder; + +pub use scan_folder::*; diff --git a/src/filesystem/scan_folder.rs b/src/filesystem/scan_folder.rs new file mode 100644 index 0000000..a8d21cc --- /dev/null +++ b/src/filesystem/scan_folder.rs @@ -0,0 +1,54 @@ +#[allow(dead_code)] + +use std::collections::HashMap; +use std::env; +use std::io; +use std::fs; +use std::os::unix::fs::MetadataExt; // TODO: support other OSs +use ::std::{thread, time}; + +use ::std::sync::atomic::{AtomicBool, Ordering}; + +use failure; + +use termion::event::Key; +use termion::raw::IntoRawMode; +use tui::backend::TermionBackend; +use tui::layout::Rect; +use tui::widgets::Widget; +use tui::Terminal; + +use std::process; + +use walkdir::WalkDir; + +use ::std::fmt; + +use std::path::PathBuf; + +use ::tui::backend::Backend; +use ::std::sync::Arc; + +use ::std::io::stdin; +use ::termion::input::TermRead; +use ::termion::event::Event; + +pub fn scan_folder (path: PathBuf) -> HashMap { + let mut file_sizes: HashMap = HashMap::new(); + let path_length = path.components().count() + 1; + for entry in WalkDir::new(path).into_iter().filter_map(|e| e.ok()) { + let entry_path = entry.path().clone(); + // all_files.push(entry_path.clone()); + match fs::metadata(entry_path.display().to_string()) { + Ok(file_metadata) => { + let file_size_entry_name = entry_path.iter().take(path_length).last().expect("failed to get path name"); // TODO: less hacky (also, 3 should be the length of the base dir) + let file_size_entry = file_sizes.entry(String::from(file_size_entry_name.to_string_lossy())).or_insert(0); + *file_size_entry += file_metadata.blocks() * 512; + }, + Err(_e) => { + // println!("\rerror opening {:?} {:?}", entry, e); // TODO: look into these + } + } + } + file_sizes +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..fe76de6 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,154 @@ +#[allow(dead_code)] +mod util; + +#[cfg(test)] +mod tests; + +use std::env; +use std::io; +use ::std::{thread, time}; +use ::std::thread::park_timeout; + +use ::std::io::stdin; +use ::termion::input::TermRead; +use ::termion::event::Event; +use ::std::sync::atomic::{AtomicBool, Ordering}; + +use failure; + +use termion::event::Key; +use termion::raw::IntoRawMode; +use tui::backend::TermionBackend; +use tui::widgets::Widget; +use tui::Terminal; + +use std::process; + +use std::path::PathBuf; + +use ::tui::backend::Backend; +use ::std::sync::{Arc, Mutex}; + +mod filesystem; +mod display; + +use filesystem::scan_folder; +use display::state::{State, calculate_percentages}; +use display::RectangleGrid; + +fn main() { + if let Err(err) = try_main() { + eprintln!("Error: {}", err); + process::exit(2); + } +} + +fn try_main() -> Result<(), failure::Error> { + match io::stdout().into_raw_mode() { + Ok(stdout) => { + let terminal_backend = TermionBackend::new(stdout); + let keyboard_events = KeyboardEvents {}; + start(terminal_backend, Box::new(keyboard_events), env::current_dir()?); + } + Err(_) => failure::bail!( + "Failed to get stdout: if you are trying to pipe 'bandwhich' you should use the --raw flag" + ), + } + Ok(()) +} + + +#[derive(Clone)] +pub struct KeyboardEvents; + +impl Iterator for KeyboardEvents { + type Item = Event; + fn next(&mut self) -> Option { + match stdin().events().next() { + Some(Ok(ev)) => Some(ev), + _ => None, + } + } +} + +pub fn start(terminal_backend: B, keyboard_events: Box + Send>, path: PathBuf) +where + B: Backend + Send + 'static, +{ + let mut active_threads = vec![]; + let running = Arc::new(AtomicBool::new(true)); + let mut terminal = Terminal::new(terminal_backend).expect("failed to create terminal"); + terminal.clear().expect("failed to clear terminal"); + terminal.hide_cursor().expect("failed to hide cursor"); + + let state = Arc::new(Mutex::new(State::new())); + + let display_handler = thread::Builder::new() + .name("display_handler".to_string()) + .spawn({ + let running = running.clone(); + let state = state.clone(); + move || { + while running.load(Ordering::Acquire) { + terminal.draw(|mut f| { + let mut full_screen = f.size(); + full_screen.width -= 1; + full_screen.height -= 1; + state.lock().unwrap().set_tiles(full_screen); + RectangleGrid::new((*state.lock().unwrap().tiles).to_vec()).render(&mut f, full_screen); + }).expect("failed to draw"); + park_timeout(time::Duration::from_millis(1000)); // TODO: we might not need this... we can trigger the display on events + } + terminal.clear().unwrap(); + } + }) + .unwrap(); + + active_threads.push( + thread::Builder::new() + .name("stdin_handler".to_string()) + .spawn({ + let running = running.clone(); + let state = state.clone(); + let display_handler = display_handler.thread().clone(); + move || { + for evt in keyboard_events { + match evt { + Event::Key(Key::Ctrl('c')) | Event::Key(Key::Char('q')) => { + running.store(false, Ordering::Release); + display_handler.unpark(); + break; + } + Event::Key(Key::Char('l')) => { + state.lock().unwrap().move_selected_right(); + display_handler.unpark(); + } + Event::Key(Key::Char('h')) => { + state.lock().unwrap().move_selected_left(); + display_handler.unpark(); + } + Event::Key(Key::Char('j')) => { + state.lock().unwrap().move_selected_down(); + display_handler.unpark(); + } + Event::Key(Key::Char('k')) => { + state.lock().unwrap().move_selected_up(); + display_handler.unpark(); + } + _ => (), + }; + } + } + }) + .unwrap(), + ); + active_threads.push(display_handler); + + let file_sizes = scan_folder(path); + let file_percentages = calculate_percentages(file_sizes); + state.lock().unwrap().set_file_percentages(file_percentages); + for thread_handler in active_threads { + thread_handler.join().unwrap() + } + +} diff --git a/src/rectangle_grid.rs b/src/rectangle_grid.rs new file mode 100644 index 0000000..c035d33 --- /dev/null +++ b/src/rectangle_grid.rs @@ -0,0 +1,322 @@ +use tui::buffer::Buffer; +use tui::layout::Rect; +use tui::style::{Style, Color}; +use tui::symbols::line; +use tui::widgets::{Borders, Widget}; + +#[derive(Clone, Debug)] +pub struct RectWithText { + pub rect: Rect, + pub text: String, + pub selected: bool, +} + +#[derive(Clone)] +pub struct RectangleGrid { + rectangles: Vec +} + +// impl<'a> Default for RectangleGrid<'a> { +// fn default() -> RectangleGrid<'a> { +// RectangleGrid { +// title: None, +// title_style: Default::default(), +// borders: Borders::NONE, +// border_style: Default::default(), +// style: Default::default(), +// } +// } +// } + +pub struct BoundariesToUse { + pub TOP_RIGHT: String, + pub VERTICAL: String, + pub HORIZONTAL: String, + pub TOP_LEFT: String, + pub BOTTOM_RIGHT: String, + pub BOTTOM_LEFT: String, + pub VERTICAL_LEFT: String, + pub VERTICAL_RIGHT: String, + pub HORIZONTAL_DOWN: String, + pub HORIZONTAL_UP: String, + pub CROSS: String, +} + +pub mod boundaries { + pub const TOP_RIGHT: &str = "┐"; + pub const VERTICAL: &str = "│"; + pub const HORIZONTAL: &str = "─"; + pub const TOP_LEFT: &str = "┌"; + pub const BOTTOM_RIGHT: &str = "┘"; + pub const BOTTOM_LEFT: &str = "└"; + pub const VERTICAL_LEFT: &str = "┤"; + pub const VERTICAL_RIGHT: &str = "├"; + pub const HORIZONTAL_DOWN: &str = "┬"; + pub const HORIZONTAL_UP: &str = "┴"; + pub const CROSS: &str = "┼"; +} + + +pub mod selected_boundaries { + pub const TOP_RIGHT: &str = "╗"; + pub const VERTICAL: &str = "║"; + pub const HORIZONTAL: &str = "═"; + pub const TOP_LEFT: &str = "╔"; + pub const BOTTOM_RIGHT: &str = "╝"; + pub const BOTTOM_LEFT: &str = "╚"; + pub const VERTICAL_LEFT: &str = "╣"; + pub const VERTICAL_RIGHT: &str = "╠"; + pub const HORIZONTAL_DOWN: &str = "╦"; + pub const HORIZONTAL_UP: &str = "╩"; + pub const CROSS: &str = "╬"; +} + +impl<'a> RectangleGrid { + pub fn new (rectangles: Vec) -> Self { + RectangleGrid { rectangles } + } +} + +fn truncate_middle(row: &str, max_length: u16) -> String { + if max_length <= 6 { + String::from(".") // TODO: make sure this never happens +// } else if max_length == 4 { +// String::from("[..]") + } else if row.len() as u16 > max_length { + let first_slice = &row[0..(max_length as usize / 2) - 2]; + let second_slice = &row[(row.len() - (max_length / 2) as usize + 2)..row.len()]; + format!("{}[..]{}", first_slice, second_slice) + } else { + row.to_string() + } +} + +impl<'a> Widget for RectangleGrid { + fn draw(&mut self, area: Rect, buf: &mut Buffer) { + if area.width < 2 || area.height < 2 { + return; + } + for rect_with_text in &self.rectangles { + + let rect_boundary_chars = BoundariesToUse { + TOP_RIGHT: String::from(boundaries::TOP_RIGHT), + VERTICAL: String::from(boundaries::VERTICAL), + HORIZONTAL: String::from(boundaries::HORIZONTAL), + TOP_LEFT: String::from(boundaries::TOP_LEFT), + BOTTOM_RIGHT: String::from(boundaries::BOTTOM_RIGHT), + BOTTOM_LEFT: String::from(boundaries::BOTTOM_LEFT), + VERTICAL_LEFT: String::from(boundaries::VERTICAL_LEFT), + VERTICAL_RIGHT: String::from(boundaries::VERTICAL_RIGHT), + HORIZONTAL_DOWN: String::from(boundaries::HORIZONTAL_DOWN), + HORIZONTAL_UP: String::from(boundaries::HORIZONTAL_UP), + CROSS: String::from(boundaries::CROSS), + }; + let rect = rect_with_text.rect; + let max_text_length = if rect.width > 4 { rect.width - 4 } else { 0 }; + // TODO: we should not accept a rectangle with a width of less than 8 so that the text + // will be at least partly legible... these rectangles should be created with a small + // height instead + let display_text = truncate_middle(&rect_with_text.text, max_text_length); + let text_length = display_text.len(); // TODO: better + + let text_start_position = ((rect.width - text_length as u16) as f64 / 2.0).ceil() as u16 + rect.x; + + + + + let text_style = if rect_with_text.selected { + Style::default().bg(Color::White).fg(Color::Black) + } else { + Style::default() + }; + buf.set_string(text_start_position, rect.height / 2 + rect.y, display_text, text_style); + + for x in rect.x..(rect.x + rect.width + 1) { + if x == rect.x { + let current_symbol_top = &buf.get(x, rect.y).symbol; + if current_symbol_top == &rect_boundary_chars.CROSS || current_symbol_top == &rect_boundary_chars.HORIZONTAL_DOWN { + // no-op + } else if current_symbol_top == &rect_boundary_chars.TOP_RIGHT || current_symbol_top == &rect_boundary_chars.HORIZONTAL { + buf.get_mut(x, rect.y) // TODO: do not get twice? + .set_symbol(&rect_boundary_chars.HORIZONTAL_DOWN); + } else if current_symbol_top == &rect_boundary_chars.BOTTOM_LEFT || current_symbol_top == &rect_boundary_chars.VERTICAL || current_symbol_top == &rect_boundary_chars.VERTICAL_RIGHT { + buf.get_mut(x, rect.y) // TODO: do not get twice? + .set_symbol(&rect_boundary_chars.VERTICAL_RIGHT); + } else if current_symbol_top == &rect_boundary_chars.HORIZONTAL_UP || current_symbol_top == &rect_boundary_chars.BOTTOM_LEFT || current_symbol_top == &rect_boundary_chars.VERTICAL_LEFT { + buf.get_mut(x, rect.y) // TODO: do not get twice? + .set_symbol(&rect_boundary_chars.CROSS); + } else { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.TOP_LEFT); + // .set_style(self.border_style); + } + + let current_symbol_bottom = &buf.get(x, rect.y + rect.height).symbol; + if current_symbol_bottom == &rect_boundary_chars.BOTTOM_RIGHT || current_symbol_bottom == &rect_boundary_chars.HORIZONTAL { + buf.get_mut(x, rect.y + rect.height) + .set_symbol(&rect_boundary_chars.HORIZONTAL_UP); + } else if current_symbol_bottom == &rect_boundary_chars.VERTICAL { + buf.get_mut(x, rect.y + rect.height) + .set_symbol(&rect_boundary_chars.VERTICAL_RIGHT); + } else { + buf.get_mut(x, rect.y + rect.height) + .set_symbol(&rect_boundary_chars.BOTTOM_LEFT); + } + } else if x == rect.x + rect.width { + let current_symbol_top = &buf.get(x, rect.y).symbol; + if current_symbol_top == &rect_boundary_chars.CROSS { + // no-op + } else if current_symbol_top == &rect_boundary_chars.TOP_LEFT || current_symbol_top == &rect_boundary_chars.TOP_RIGHT || current_symbol_top == &rect_boundary_chars.HORIZONTAL { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.HORIZONTAL_DOWN); + } else if current_symbol_top == &rect_boundary_chars.HORIZONTAL_UP { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.CROSS); + } else if current_symbol_top == &rect_boundary_chars.BOTTOM_RIGHT { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.VERTICAL_LEFT); + } else { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.TOP_RIGHT); + } + let current_symbol_bottom = &buf.get(x, rect.y + rect.height).symbol; + if current_symbol_bottom == &rect_boundary_chars.BOTTOM_LEFT || current_symbol_bottom == &rect_boundary_chars.BOTTOM_RIGHT || current_symbol_bottom == &rect_boundary_chars.HORIZONTAL { + buf.get_mut(x, rect.y + rect.height) + .set_symbol(&rect_boundary_chars.HORIZONTAL_UP); + } else { + buf.get_mut(x, rect.y + rect.height) + .set_symbol(&rect_boundary_chars.BOTTOM_RIGHT); + } + } else { + let current_symbol_top = &buf.get(x, rect.y).symbol; + if current_symbol_top == &rect_boundary_chars.CROSS || current_symbol_top == &rect_boundary_chars.HORIZONTAL_UP { + // no-op + } else if current_symbol_top == &rect_boundary_chars.TOP_LEFT || current_symbol_top == &rect_boundary_chars.TOP_RIGHT { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.HORIZONTAL_DOWN); + } else if current_symbol_top == &rect_boundary_chars.BOTTOM_LEFT || current_symbol_top == &rect_boundary_chars.BOTTOM_RIGHT { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.HORIZONTAL_UP); + } else if current_symbol_top == &rect_boundary_chars.VERTICAL { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.CROSS); + } else { + buf.get_mut(x, rect.y) + .set_symbol(&rect_boundary_chars.HORIZONTAL); + } + let current_symbol_bottom = &buf.get(x, rect.y + rect.height).symbol; + if current_symbol_bottom == &rect_boundary_chars.BOTTOM_LEFT || current_symbol_bottom == &rect_boundary_chars.BOTTOM_RIGHT { + buf.get_mut(x, rect.y + rect.height) + .set_symbol(&rect_boundary_chars.HORIZONTAL_UP); + } else if current_symbol_bottom == &rect_boundary_chars.VERTICAL { + buf.get_mut(x, rect.y + rect.height) + .set_symbol(&rect_boundary_chars.CROSS); + } else { + buf.get_mut(x, rect.y + rect.height) + .set_symbol(&rect_boundary_chars.HORIZONTAL); + } + } + } + + // sides + for y in (rect.y + 1)..(rect.y + rect.height) { + let current_symbol_left = &buf.get(rect.x, y).symbol; + if current_symbol_left == &rect_boundary_chars.HORIZONTAL { + buf.get_mut(rect.x, y) + .set_symbol(&rect_boundary_chars.CROSS); + } else { + buf.get_mut(rect.x, y) + .set_symbol(&rect_boundary_chars.VERTICAL); + } + let current_symbol_right = &buf.get(rect.x + rect.width, y).symbol; + if current_symbol_right == &rect_boundary_chars.HORIZONTAL { + buf.get_mut(rect.x + rect.width, y) + .set_symbol(&rect_boundary_chars.CROSS); + } else { + buf.get_mut(rect.x + rect.width, y) + .set_symbol(&rect_boundary_chars.VERTICAL); + } + } + + } + +// self.background(area, buf, self.style.bg); +// +// // Sides +// if self.borders.intersects(Borders::LEFT) { +// for y in area.top()..area.bottom() { +// buf.get_mut(area.left(), y) +// .set_symbol(line::VERTICAL) +// .set_style(self.border_style); +// } +// } +// if self.borders.intersects(Borders::TOP) { +// for x in area.left()..area.right() { +// buf.get_mut(x, area.top()) +// .set_symbol(line::HORIZONTAL) +// .set_style(self.border_style); +// } +// } +// if self.borders.intersects(Borders::RIGHT) { +// let x = area.right() - 1; +// for y in area.top()..area.bottom() { +// buf.get_mut(x, y) +// .set_symbol(line::VERTICAL) +// .set_style(self.border_style); +// } +// } +// if self.borders.intersects(Borders::BOTTOM) { +// let y = area.bottom() - 1; +// for x in area.left()..area.right() { +// buf.get_mut(x, y) +// .set_symbol(line::HORIZONTAL) +// .set_style(self.border_style); +// } +// } +// +// // Corners +// if self.borders.contains(Borders::LEFT | Borders::TOP) { +// buf.get_mut(area.left(), area.top()) +// .set_symbol(line::TOP_LEFT) +// .set_style(self.border_style); +// } +// if self.borders.contains(Borders::RIGHT | Borders::TOP) { +// buf.get_mut(area.right() - 1, area.top()) +// .set_symbol(line::TOP_RIGHT) +// .set_style(self.border_style); +// } +// if self.borders.contains(Borders::LEFT | Borders::BOTTOM) { +// buf.get_mut(area.left(), area.bottom() - 1) +// .set_symbol(line::BOTTOM_LEFT) +// .set_style(self.border_style); +// } +// if self.borders.contains(Borders::RIGHT | Borders::BOTTOM) { +// buf.get_mut(area.right() - 1, area.bottom() - 1) +// .set_symbol(line::BOTTOM_RIGHT) +// .set_style(self.border_style); +// } +// +// if area.width > 2 { +// if let Some(title) = self.title { +// let lx = if self.borders.intersects(Borders::LEFT) { +// 1 +// } else { +// 0 +// }; +// let rx = if self.borders.intersects(Borders::RIGHT) { +// 1 +// } else { +// 0 +// }; +// let width = area.width - lx - rx; +// buf.set_stringn( +// area.left() + lx, +// area.top(), +// title, +// width as usize, +// self.title_style, +// ); +// } +// } + } +} diff --git a/src/tests/cases/mod.rs b/src/tests/cases/mod.rs new file mode 100644 index 0000000..1717c13 --- /dev/null +++ b/src/tests/cases/mod.rs @@ -0,0 +1,2 @@ +pub mod test_utils; +pub mod ui; diff --git a/src/tests/cases/snapshots/ui__eleven_files.snap b/src/tests/cases/snapshots/ui__eleven_files.snap new file mode 100644 index 0000000..dbf7380 --- /dev/null +++ b/src/tests/cases/snapshots/ui__eleven_files.snap @@ -0,0 +1,55 @@ +--- +source: src/tests/cases/ui.rs +expression: "&terminal_draw_events_mirror[0]" +--- +┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬──────────────────────────────────────────┬─────┬─────┬─────────┐ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ file7 151.6K (33%) │ file10 53.2K (12%) │ . │ . │ . │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +├──────────────────────────────────────────┬──────────────────────────────────────────┬─────────────────────────────────────┴────┬─────────────────────────────────────└────┬└────┬└─────────┘ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ file11 53.2K (12%) │ file6 53.2K (12%) │ file8 53.2K (12%) │ file9 53.2K (12%) │ . │ f[..]) │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ │ +└──────────────────────────────────────────┴──────────────────────────────────────────┴──────────────────────────────────────────┴──────────────────────────────────────────┴─────┴──────────┘ + diff --git a/src/tests/cases/snapshots/ui__two_large_files_one_small_file.snap b/src/tests/cases/snapshots/ui__two_large_files_one_small_file.snap new file mode 100644 index 0000000..231642d --- /dev/null +++ b/src/tests/cases/snapshots/ui__two_large_files_one_small_file.snap @@ -0,0 +1,55 @@ +--- +source: src/tests/cases/ui.rs +expression: "&terminal_draw_events_mirror[0]" +--- +┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─────────────────────────────────────┐ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ file2 8.2K (40%) │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│ file1 4.1K (20%) │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ file3 8.2K (40%) │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴─────────────────────────────────────┘ + diff --git a/src/tests/cases/test_utils.rs b/src/tests/cases/test_utils.rs new file mode 100644 index 0000000..d561062 --- /dev/null +++ b/src/tests/cases/test_utils.rs @@ -0,0 +1,32 @@ +use crate::tests::fakes::{ + KeyboardEvents, + TerminalEvent, TestBackend, +}; +use std::iter; + +use ::termion::event::{Event, Key}; +use std::sync::{Arc, Mutex}; + +pub fn sleep_and_quit_events(sleep_num: usize) -> Box { + let mut events: Vec> = iter::repeat(None).take(sleep_num).collect(); + events.push(Some(Event::Key(Key::Ctrl('c')))); + Box::new(KeyboardEvents::new(events)) +} + +type BackendWithStreams = ( + Arc>>, + Arc>>, + TestBackend, +); +pub fn test_backend_factory(w: u16, h: u16) -> BackendWithStreams { + let terminal_events: Arc>> = Arc::new(Mutex::new(Vec::new())); + let terminal_draw_events: Arc>> = Arc::new(Mutex::new(Vec::new())); + + let backend = TestBackend::new( + terminal_events.clone(), + terminal_draw_events.clone(), + Arc::new(Mutex::new(w)), + Arc::new(Mutex::new(h)), + ); + (terminal_events, terminal_draw_events, backend) +} diff --git a/src/tests/cases/ui.rs b/src/tests/cases/ui.rs new file mode 100644 index 0000000..3706420 --- /dev/null +++ b/src/tests/cases/ui.rs @@ -0,0 +1,130 @@ +use crate::tests::fakes::TerminalEvent::*; +use ::insta::assert_snapshot; + +use crate::tests::cases::test_utils::{test_backend_factory, sleep_and_quit_events}; +use std::path::PathBuf; + +use crate::start; + +use std::env; +use std::fs::{File, create_dir}; +use std::io::prelude::*; +use uuid::Uuid; + +fn create_temp_dir () -> Result { + let mut dir = env::temp_dir(); + let temp_dir_name = Uuid::new_v4(); + dir.push(temp_dir_name.to_string()); + + create_dir(&dir)?; + Ok(dir) +} + +fn create_temp_file (path: PathBuf, size: usize) -> Result<(), failure::Error> { + let mut file = File::create(path)?; + let mut pos = 0; + while pos < size { + let bytes_written = file.write(b"W")?; + pos += bytes_written; + } + Ok(()) +} + +#[test] +fn two_large_files_one_small_file () { + + let (terminal_events, terminal_draw_events, backend) = test_backend_factory(190, 50); + let keyboard_events = sleep_and_quit_events(2); + let temp_dir_path = create_temp_dir().expect("failed to create temp dir"); + + let mut file_1_path = PathBuf::from(&temp_dir_path); + file_1_path.push("file1"); + create_temp_file(file_1_path, 4000).expect("failed to create temp file"); + + let mut file_2_path = PathBuf::from(&temp_dir_path); + file_2_path.push("file2"); + create_temp_file(file_2_path, 5000).expect("failed to create temp file"); + + let mut file_3_path = PathBuf::from(&temp_dir_path); + file_3_path.push("file3"); + create_temp_file(file_3_path, 5000).expect("failed to create temp file"); + + start(backend, keyboard_events, temp_dir_path.clone()); + std::fs::remove_dir_all(temp_dir_path).expect("failed to remove temporary folder"); + let terminal_draw_events_mirror = terminal_draw_events.lock().unwrap(); + + let expected_terminal_events = vec![Clear, HideCursor, Draw, Flush, Draw, Flush, Clear, ShowCursor]; + + assert_eq!( + &terminal_events.lock().unwrap()[..], + &expected_terminal_events[..] + ); + + assert_eq!(terminal_draw_events_mirror.len(), 2); + assert_snapshot!(&terminal_draw_events_mirror[1]); +} + +#[test] +fn eleven_files () { + + let (terminal_events, terminal_draw_events, backend) = test_backend_factory(190, 50); + let keyboard_events = sleep_and_quit_events(2); + let temp_dir_path = create_temp_dir().expect("failed to create temp dir"); + + let mut file_1_path = PathBuf::from(&temp_dir_path); + file_1_path.push("file1"); + create_temp_file(file_1_path, 5000).expect("failed to create temp file"); + + let mut file_2_path = PathBuf::from(&temp_dir_path); + file_2_path.push("file2"); + create_temp_file(file_2_path, 5000).expect("failed to create temp file"); + + let mut file_3_path = PathBuf::from(&temp_dir_path); + file_3_path.push("file3"); + create_temp_file(file_3_path, 5000).expect("failed to create temp file"); + + let mut file_4_path = PathBuf::from(&temp_dir_path); + file_4_path.push("file4"); + create_temp_file(file_4_path, 5000).expect("failed to create temp file"); + + let mut file_5_path = PathBuf::from(&temp_dir_path); + file_5_path.push("file5"); + create_temp_file(file_5_path, 5000).expect("failed to create temp file"); + + let mut file_6_path = PathBuf::from(&temp_dir_path); + file_6_path.push("file6"); + create_temp_file(file_6_path, 50000).expect("failed to create temp file"); + + let mut file_7_path = PathBuf::from(&temp_dir_path); + file_7_path.push("file7"); + create_temp_file(file_7_path, 150000).expect("failed to create temp file"); + + let mut file_8_path = PathBuf::from(&temp_dir_path); + file_8_path.push("file8"); + create_temp_file(file_8_path, 50000).expect("failed to create temp file"); + + let mut file_9_path = PathBuf::from(&temp_dir_path); + file_9_path.push("file9"); + create_temp_file(file_9_path, 50000).expect("failed to create temp file"); + + let mut file_10_path = PathBuf::from(&temp_dir_path); + file_10_path.push("file10"); + create_temp_file(file_10_path, 50000).expect("failed to create temp file"); + + let mut file_11_path = PathBuf::from(&temp_dir_path); + file_11_path.push("file11"); + create_temp_file(file_11_path, 50000).expect("failed to create temp file"); + + start(backend, keyboard_events, temp_dir_path.clone()); + std::fs::remove_dir_all(temp_dir_path).expect("failed to remove temporary folder"); + let terminal_draw_events_mirror = terminal_draw_events.lock().unwrap(); + + let expected_terminal_events = vec![Clear, HideCursor, Draw, Flush, Draw, Flush, Clear, ShowCursor]; + assert_eq!( + &terminal_events.lock().unwrap()[..], + &expected_terminal_events[..] + ); + + assert_eq!(terminal_draw_events_mirror.len(), 2); + assert_snapshot!(&terminal_draw_events_mirror[1]); +} diff --git a/src/tests/fakes/fake_input.rs b/src/tests/fakes/fake_input.rs new file mode 100644 index 0000000..178cd26 --- /dev/null +++ b/src/tests/fakes/fake_input.rs @@ -0,0 +1,28 @@ +use ::std::{thread, time}; +use ::termion::event::Event; + +pub struct KeyboardEvents { + pub events: Vec>, +} + +impl KeyboardEvents { + pub fn new(mut events: Vec>) -> Self { + events.reverse(); // this is so that we do not have to shift the array + KeyboardEvents { events } + } +} +impl Iterator for KeyboardEvents { + type Item = Event; + fn next(&mut self) -> Option { + match self.events.pop() { + Some(ev) => match ev { + Some(ev) => Some(ev), + None => { + thread::sleep(time::Duration::from_millis(900)); + self.next() + } + }, + None => None, + } + } +} diff --git a/src/tests/fakes/fake_output.rs b/src/tests/fakes/fake_output.rs new file mode 100644 index 0000000..1950dec --- /dev/null +++ b/src/tests/fakes/fake_output.rs @@ -0,0 +1,115 @@ +use ::std::collections::HashMap; +use ::std::io; +use ::std::sync::{Arc, Mutex}; +use ::tui::backend::Backend; +use ::tui::buffer::Cell; +use ::tui::layout::Rect; + +#[derive(Hash, Debug, PartialEq)] +pub enum TerminalEvent { + Clear, + HideCursor, + ShowCursor, + GetCursor, + Flush, + Draw, +} + +pub struct TestBackend { + pub events: Arc>>, + pub draw_events: Arc>>, + terminal_width: Arc>, + terminal_height: Arc>, +} + +impl TestBackend { + pub fn new( + log: Arc>>, + draw_log: Arc>>, + terminal_width: Arc>, + terminal_height: Arc>, + ) -> TestBackend { + TestBackend { + events: log, + draw_events: draw_log, + terminal_width, + terminal_height, + } + } +} + +#[derive(Hash, Eq, PartialEq)] +struct Point { + x: u16, + y: u16, +} + +impl Backend for TestBackend { + fn clear(&mut self) -> io::Result<()> { + self.events.lock().unwrap().push(TerminalEvent::Clear); + Ok(()) + } + + fn hide_cursor(&mut self) -> io::Result<()> { + self.events.lock().unwrap().push(TerminalEvent::HideCursor); + Ok(()) + } + + fn show_cursor(&mut self) -> io::Result<()> { + self.events.lock().unwrap().push(TerminalEvent::ShowCursor); + Ok(()) + } + + fn get_cursor(&mut self) -> io::Result<(u16, u16)> { + self.events.lock().unwrap().push(TerminalEvent::GetCursor); + Ok((0, 0)) + } + + fn set_cursor(&mut self, _x: u16, _y: u16) -> io::Result<()> { + Ok(()) + } + + fn draw<'a, I>(&mut self, content: I) -> io::Result<()> + where + I: Iterator, + { + // use std::fmt::Write; + self.events.lock().unwrap().push(TerminalEvent::Draw); + let mut string = String::with_capacity(content.size_hint().0 * 3); + let mut coordinates = HashMap::new(); + for (x, y, cell) in content { + coordinates.insert(Point { x, y }, cell); + } + let terminal_height = self.terminal_height.lock().unwrap(); + let terminal_width = self.terminal_width.lock().unwrap(); + for y in 0..*terminal_height { + for x in 0..*terminal_width { + match coordinates.get(&Point { x, y }) { + Some(cell) => { + // this will contain no style information at all + // should be good enough for testing + string.push_str(&cell.symbol); + } + None => { + string.push_str(" "); + } + } + } + string.push_str("\n"); + } + self.draw_events.lock().unwrap().push(string); + Ok(()) + } + + fn size(&self) -> io::Result { + let terminal_height = self.terminal_height.lock().unwrap(); + let terminal_width = self.terminal_width.lock().unwrap(); + + Ok(Rect::new(0, 0, *terminal_width, *terminal_height)) + } + + fn flush(&mut self) -> io::Result<()> { + self.events.lock().unwrap().push(TerminalEvent::Flush); + Ok(()) + } +} diff --git a/src/tests/fakes/mod.rs b/src/tests/fakes/mod.rs new file mode 100644 index 0000000..dcd441b --- /dev/null +++ b/src/tests/fakes/mod.rs @@ -0,0 +1,5 @@ +mod fake_input; +mod fake_output; + +pub use fake_input::*; +pub use fake_output::*; diff --git a/src/tests/mod.rs b/src/tests/mod.rs new file mode 100644 index 0000000..3e6e8f9 --- /dev/null +++ b/src/tests/mod.rs @@ -0,0 +1,2 @@ +pub mod cases; +pub mod fakes; diff --git a/src/util/event.rs b/src/util/event.rs new file mode 100644 index 0000000..e58fe43 --- /dev/null +++ b/src/util/event.rs @@ -0,0 +1,83 @@ +use std::io; +use std::sync::mpsc; +use std::thread; +use std::time::Duration; + +use termion::event::Key; +use termion::input::TermRead; + +pub enum Event { + Input(I), + Tick, +} + +/// A small event handler that wrap termion input and tick events. Each event +/// type is handled in its own thread and returned to a common `Receiver` +pub struct Events { + rx: mpsc::Receiver>, + input_handle: thread::JoinHandle<()>, + tick_handle: thread::JoinHandle<()>, +} + +#[derive(Debug, Clone, Copy)] +pub struct Config { + pub exit_key: Key, + pub tick_rate: Duration, +} + +impl Default for Config { + fn default() -> Config { + Config { + exit_key: Key::Char('q'), + tick_rate: Duration::from_millis(250), + } + } +} + +impl Events { + pub fn new() -> Events { + Events::with_config(Config::default()) + } + + pub fn with_config(config: Config) -> Events { + let (tx, rx) = mpsc::channel(); + let input_handle = { + let tx = tx.clone(); + thread::spawn(move || { + let stdin = io::stdin(); + for evt in stdin.keys() { + match evt { + Ok(key) => { + if let Err(_) = tx.send(Event::Input(key)) { + return; + } + if key == config.exit_key { + return; + } + } + Err(_) => {} + } + } + }) + }; + let tick_handle = { + let tx = tx.clone(); + thread::spawn(move || { + let tx = tx.clone(); + loop { + tx.send(Event::Tick).unwrap(); + thread::sleep(config.tick_rate); + } + }) + }; + Events { + rx, + input_handle, + tick_handle, + } + } + + pub fn next(&self) -> Result, mpsc::RecvError> { + self.rx.recv() + } +} diff --git a/src/util/mod.rs b/src/util/mod.rs new file mode 100644 index 0000000..34222ab --- /dev/null +++ b/src/util/mod.rs @@ -0,0 +1,77 @@ +#[cfg(feature = "termion")] +pub mod event; + +// use rand::distributions::{Distribution, Uniform}; +// use rand::rngs::ThreadRng; +// +// #[derive(Clone)] +// pub struct RandomSignal { +// distribution: Uniform, +// rng: ThreadRng, +// } +// +// impl RandomSignal { +// pub fn new(lower: u64, upper: u64) -> RandomSignal { +// RandomSignal { +// distribution: Uniform::new(lower, upper), +// rng: rand::thread_rng(), +// } +// } +// } +// +// impl Iterator for RandomSignal { +// type Item = u64; +// fn next(&mut self) -> Option { +// Some(self.distribution.sample(&mut self.rng)) +// } +// } +// +// #[derive(Clone)] +// pub struct SinSignal { +// x: f64, +// interval: f64, +// period: f64, +// scale: f64, +// } +// +// impl SinSignal { +// pub fn new(interval: f64, period: f64, scale: f64) -> SinSignal { +// SinSignal { +// x: 0.0, +// interval, +// period, +// scale, +// } +// } +// } +// +// impl Iterator for SinSignal { +// type Item = (f64, f64); +// fn next(&mut self) -> Option { +// let point = (self.x, (self.x * 1.0 / self.period).sin() * self.scale); +// self.x += self.interval; +// Some(point) +// } +// } +// +// pub struct TabsState<'a> { +// pub titles: Vec<&'a str>, +// pub index: usize, +// } +// +// impl<'a> TabsState<'a> { +// pub fn new(titles: Vec<&'a str>) -> TabsState { +// TabsState { titles, index: 0 } +// } +// pub fn next(&mut self) { +// self.index = (self.index + 1) % self.titles.len(); +// } +// +// pub fn previous(&mut self) { +// if self.index > 0 { +// self.index -= 1; +// } else { +// self.index = self.titles.len() - 1; +// } +// } +// }