about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1450
-rw-r--r--Cargo.toml33
-rw-r--r--Config.toml2
-rw-r--r--proptest-regressions/description.txt7
-rw-r--r--proptest-regressions/display/draw_box.txt12
-rw-r--r--proptest-regressions/display/viewport.txt7
-rw-r--r--proptest-regressions/types/entity_map.txt9
-rw-r--r--proptest-regressions/types/mod.txt8
-rw-r--r--rustfmt.toml1
-rw-r--r--src/cli.yml46
-rw-r--r--src/description.rs93
-rw-r--r--src/display/color.rs163
-rw-r--r--src/display/draw_box.rs274
-rw-r--r--src/display/mod.rs52
-rw-r--r--src/display/utils.rs9
-rw-r--r--src/display/viewport.rs303
-rw-r--r--src/entities/character.rs51
-rw-r--r--src/entities/creature.rs63
-rw-r--r--src/entities/entity.rs125
-rw-r--r--src/entities/entity_char.rs24
-rw-r--r--src/entities/environment.rs36
-rw-r--r--src/entities/item.rs50
-rw-r--r--src/entities/mod.rs20
-rw-r--r--src/entities/raw_types.rs110
-rw-r--r--src/entities/raws.rs38
-rw-r--r--src/entities/raws/gormlak.toml10
-rw-r--r--src/entities/raws/noodles.json15
-rw-r--r--src/entities/util.rs72
-rw-r--r--src/game.rs617
-rw-r--r--src/level_gen/cave_automata.rs120
-rw-r--r--src/level_gen/mod.rs101
-rw-r--r--src/level_gen/util.rs52
-rw-r--r--src/main.rs130
-rw-r--r--src/messages.rs166
-rw-r--r--src/messages.toml27
-rw-r--r--src/settings.rs70
-rw-r--r--src/types/collision.rs9
-rw-r--r--src/types/command.rs41
-rw-r--r--src/types/direction.rs13
-rw-r--r--src/types/entity_map.rs430
-rw-r--r--src/types/menu.rs31
-rw-r--r--src/types/mod.rs504
-rw-r--r--src/util/mod.rs7
-rw-r--r--src/util/promise.rs160
-rw-r--r--src/util/static_cfg.rs147
-rw-r--r--src/util/template.rs362
-rw-r--r--src/util/trait_impls.rs17
47 files changed, 0 insertions, 6087 deletions
diff --git a/Cargo.lock b/Cargo.lock
deleted file mode 100644
index 214b78f62542..000000000000
--- a/Cargo.lock
+++ /dev/null
@@ -1,1450 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-[[package]]
-name = "adler32"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "aho-corasick"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "alga"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libm 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.2.8 (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.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "antidote"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "approx"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "arc-swap"
-version = "0.3.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "argon2rs"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
- "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "arrayvec"
-version = "0.4.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "nodrop 0.1.13 (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.58 (registry+https://github.com/rust-lang/crates.io-index)",
- "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "autocfg"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "backtrace"
-version = "0.3.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "backtrace-sys 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "backtrace-sys"
-version = "0.1.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "bit-set"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "bit-vec"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "bitflags"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "blake2-rfc"
-version = "0.2.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "bstr"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex-automata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "build_const"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "byteorder"
-version = "1.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "c2-chacha"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "cc"
-version = "1.0.37"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "cfg-if"
-version = "0.1.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "chrono"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.2.8 (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.1.0 (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.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "yaml-rust 0.3.5 (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.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "config"
-version = "0.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde-hjson 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.4.10 (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 = "constant_time_eq"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "crc"
-version = "1.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "crc32fast"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "csv"
-version = "1.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bstr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "csv-core"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "dirs"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "downcast-rs"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "dtoa"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "either"
-version = "1.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "encode_unicode"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "failure"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "failure_derive"
-version = "0.1.5"
-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.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "flate2"
-version = "1.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
- "miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "fnv"
-version = "1.0.6"
-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 = "futures"
-version = "0.1.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "getrandom"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.58 (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 = "humantime"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "include_dir"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "include_dir_impl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "include_dir_impl"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "proc-macro-hack 0.4.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.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "itertools"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "itoa"
-version = "0.4.4"
-source = "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.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "lexical-core"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "stackvector 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.58"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "libm"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "linked-hash-map"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_test 0.8.23 (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 = "log"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "log-mdc"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "log4rs"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "log-mdc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde-value 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "maplit"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "matches"
-version = "0.1.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "memchr"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "miniz-sys"
-version = "0.1.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "miniz_oxide"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "miniz_oxide_c_api"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
- "miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "nodrop"
-version = "0.1.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "nom"
-version = "4.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "nom"
-version = "5.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "lexical-core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "num-complex"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.2.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.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.1.43"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "autocfg 0.1.4 (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 = "ordered-float"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "ppv-lite86"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "prettytable-rs"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "proc-macro-hack"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "proc-macro-hack-impl"
-version = "0.4.1"
-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 = "proptest"
-version = "0.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "proptest-derive"
-version = "0.1.1"
-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.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "quick-error"
-version = "1.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "quote"
-version = "0.6.12"
-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 = "rand"
-version = "0.6.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.58 (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.0 (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.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "rand"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_pcg 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.4 (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.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_core 0.5.0 (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.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "rand_core"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "getrandom 0.1.6 (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.0 (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.58 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (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.58 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_core 0.4.0 (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.7 (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.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "rand_pcg"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_core 0.5.0 (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 = "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.54"
-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.54 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "redox_users"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "regex"
-version = "1.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "regex-automata"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.6.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "remove_dir_all"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "rust-ini"
-version = "0.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "rustc-demangle"
-version = "0.1.15"
-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 = "rusty-fork"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "ryu"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "ryu"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "scoped_threadpool"
-version = "0.1.9"
-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 = "0.8.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "serde"
-version = "1.0.92"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "serde-hjson"
-version = "0.8.2"
-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)",
- "linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "serde-value"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.92"
-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.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "serde_json"
-version = "1.0.39"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "serde_test"
-version = "0.8.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "serde_yaml"
-version = "0.8.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "dtoa 0.4.4 (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.92 (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 = "spin"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "stackvector"
-version = "1.0.6"
-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)",
- "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "static_assertions"
-version = "0.2.5"
-source = "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 = "syn"
-version = "0.14.9"
-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.12 (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 = "0.15.35"
-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.12 (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 = "synstructure"
-version = "0.10.2"
-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.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.35 (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 = "tempfile"
-version = "3.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
- "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "term"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "termion"
-version = "1.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.58 (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.54 (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 = "textwrap"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "thread-id"
-version = "3.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "thread_local"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "lazy_static 1.3.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.58 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "toml"
-version = "0.4.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "toml"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "traitobject"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "typemap"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "ucd-util"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "unicode-width"
-version = "0.1.5"
-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 = "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 = "unsafe-any"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "utf8-ranges"
-version = "1.0.3"
-source = "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 = "version_check"
-version = "0.1.5"
-source = "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 = "wait-timeout"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "winapi"
-version = "0.3.7"
-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-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "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 = "xanthous"
-version = "0.1.0"
-dependencies = [
- "alga 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
- "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "config 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "downcast-rs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
- "include_dir 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "log4rs 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "nom 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "prettytable-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "proptest 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "proptest-derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "yaml-rust"
-version = "0.3.5"
-source = "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 adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c"
-"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
-"checksum alga 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d708cb68c7106ed1844de68f50f0157a7788c2909a6926fad5a87546ef6a4ff8"
-"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
-"checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5"
-"checksum approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3"
-"checksum arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "bc4662175ead9cd84451d5c35070517777949a2ed84551764129cedb88384841"
-"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
-"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
-"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
-"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
-"checksum backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)" = "18b50f5258d1a9ad8396d2d345827875de4261b158124d4c819d9b351454fae5"
-"checksum backtrace-sys 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "5b3a000b9c543553af61bc01cbfc403b04b5caa9e421033866f2e98061eb3e61"
-"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80"
-"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb"
-"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
-"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
-"checksum bstr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc0572e02f76cb335f309b19e0a0d585b4f62788f7d26de2a13a836a637385f"
-"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
-"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
-"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"
-"checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d"
-"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
-"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
-"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
-"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
-"checksum config 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9107d78ed62b3fa5a86e7d18e647abed48cfd8f8fab6c72f4cdb982d196f7e6"
-"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
-"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
-"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
-"checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d"
-"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c"
-"checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
-"checksum downcast-rs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b92dfd5c2f75260cbf750572f95d387e7ca0ba5e3fbe9e1a33f23025be020f"
-"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e"
-"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
-"checksum encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90b2c9496c001e8cb61827acdefad780795c42264c137744cae6f7d9e3450abd"
-"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
-"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
-"checksum flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f87e68aa82b2de08a6e037f1385455759df6e445a8df5e005b4297191dbf18aa"
-"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
-"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
-"checksum futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869"
-"checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55"
-"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
-"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
-"checksum include_dir 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f41a8bee1894b3fb755d8f09ccd764650476358197a0582555f698fe84b0ae93"
-"checksum include_dir_impl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4b029199aef0fb9921fdc5623843197e6f4a035774523817599a9f55e4bf3b"
-"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
-"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
-"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
-"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
-"checksum lexical-core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3f8673fab7063c2cac37d299c8a1a7beb720e78f71500098e4a3c137fdf025bf"
-"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319"
-"checksum libm 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
-"checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
-"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
-"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
-"checksum log-mdc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7"
-"checksum log4rs 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "100052474df98158c0738a7d3f4249c99978490178b5f9f68cd835ac57adbd1b"
-"checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43"
-"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
-"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
-"checksum miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9e3ae51cea1576ceba0dde3d484d30e6e5b86dee0b2d412fe3a16a15c98202"
-"checksum miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c468f2369f07d651a5d0bb2c9079f8488a66d5466efe42d0c5c6466edcb7f71e"
-"checksum miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7fe927a42e3807ef71defb191dc87d4e24479b221e67015fe38ae2b7b447bab"
-"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
-"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
-"checksum nom 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9761d859320e381010a4f7f8ed425f2c924de33ad121ace447367c713ad561b"
-"checksum num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fcb0cf31fb3ff77e6d2a6ebd6800df7fdcd106f2ad89113c9130bcd07f93dffc"
-"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
-"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
-"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
-"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
-"checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
-"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
-"checksum prettytable-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0fd04b170004fa2daccf418a7f8253aaf033c27760b5f225889024cf66d7ac2e"
-"checksum proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8"
-"checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a"
-"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
-"checksum proptest 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2afed8cbdc8a64b58a5c021757a782351ec1afee85be374872721c84d5da5d80"
-"checksum proptest-derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08b264c54525e760fc1d39c5b2bfc96923b922a752893053b4adaafe33fa9346"
-"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
-"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
-"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
-"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c"
-"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
-"checksum rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e193067942ef6f485a349a113329140d0ab9e2168ce92274499bb0e9a4190d9d"
-"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
-"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
-"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca"
-"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_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6"
-"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
-"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
-"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
-"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
-"checksum redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe5204c3a17e97dde73f285d49be585df59ed84b50a872baf416e73b62c3828"
-"checksum regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0b2f0808e7d7e4fb1cb07feb6ff2f4bc827938f24f8c2e6a3beb7370af544bdd"
-"checksum regex-automata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ed09217220c272b29ef237a974ad58515bde75f194e3ffa7e6d0bf0f3b01f86"
-"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
-"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
-"checksum rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2"
-"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
-"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
-"checksum rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd93264e10c577503e926bd1430193eeb5d21b059148910082245309b424fae"
-"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f"
-"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
-"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
-"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 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8"
-"checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be"
-"checksum serde-hjson 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0b833c5ad67d52ced5f5938b2980f32a9c1c5ef047f0b4fb3127e7a423c76153"
-"checksum serde-value 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7a663f873dedc4eac1a559d4c6bc0d0b2c34dc5ac4702e105014b8281489e44f"
-"checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e"
-"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
-"checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5"
-"checksum serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "38b08a9a90e5260fe01c6480ec7c811606df6d3a660415808c3c3fa8ed95b582"
-"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"
-"checksum stackvector 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1c4725650978235083241fab0fdc8e694c3de37821524e7534a1a9061d1068af"
-"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5"
-"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
-"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
-"checksum syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)" = "641e117d55514d6d918490e47102f7e08d096fdde360247e4a10f7a91a8478d3"
-"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
-"checksum tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef"
-"checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
-"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea"
-"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
-"checksum thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1"
-"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
-"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
-"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
-"checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039"
-"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"
-"checksum typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "653be63c80a3296da5551e1bfd2cca35227e13cdd08c6668903ae2f4f77aa1f6"
-"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
-"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
-"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
-"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
-"checksum unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f"
-"checksum utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d50aa7650df78abf942826607c62468ce18d9019673d4a2ebe1865dbb96ffde"
-"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
-"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
-"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
-"checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
-"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
-"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-"checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992"
-"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d"
diff --git a/Cargo.toml b/Cargo.toml
deleted file mode 100644
index 1ac8853f472d..000000000000
--- a/Cargo.toml
+++ /dev/null
@@ -1,33 +0,0 @@
-[package]
-name = "xanthous"
-version = "0.1.0"
-authors = ["Griffin Smith <root@gws.fyi>"]
-edition = "2018"
-
-[dependencies]
-alga = "0.9.1"
-backtrace = "0.3"
-clap = {version = "^2.33.0", features = ["yaml"]}
-config = "*"
-downcast-rs = "^1.0.4"
-futures = "0.1.28"
-include_dir = "0.2.1"
-itertools = "*"
-lazy_static = "*"
-log = "*"
-log4rs = "*"
-maplit = "^1.0.1"
-matches = "0.1.8"
-nom = "^5.0.0"
-prettytable-rs = "^0.8"
-proptest = "0.9.3"
-proptest-derive = "*"
-rand = {version = "^0.7.0", features = ["small_rng"]}
-serde = "^1.0.8"
-serde_derive = "^1.0.8"
-serde_json = "*"
-serde_yaml = "0.8"
-termion = "*"
-toml = "^0.5.1"
-
-[dev-dependencies]
diff --git a/Config.toml b/Config.toml
deleted file mode 100644
index 30806365d28f..000000000000
--- a/Config.toml
+++ /dev/null
@@ -1,2 +0,0 @@
-[logging]
-level = "debug"
diff --git a/proptest-regressions/description.txt b/proptest-regressions/description.txt
deleted file mode 100644
index 3c4942315b45..000000000000
--- a/proptest-regressions/description.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-# Seeds for failure cases proptest has generated in the past. It is
-# automatically read and these particular cases re-run before any
-# novel cases are generated.
-#
-# It is recommended to check this file in to source control so that
-# everyone who runs the test benefits from these saved cases.
-cc 92b51b5444b913aaa6cb89d7e7175ab6a6af5b5231ba047d123bb55d43d7d272 # shrinks to descriptions = []
diff --git a/proptest-regressions/display/draw_box.txt b/proptest-regressions/display/draw_box.txt
deleted file mode 100644
index 03391a696de8..000000000000
--- a/proptest-regressions/display/draw_box.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-# Seeds for failure cases proptest has generated in the past. It is
-# automatically read and these particular cases re-run before any
-# novel cases are generated.
-#
-# It is recommended to check this file in to source control so that
-# everyone who runs the test benefits from these saved cases.
-cc 7aff36a9f7b263e62434a3f61ada1d6aaf6ff4545a463548d96815a0e98cf5f1 # shrinks to dims = Dimensions { w: 0, h: 0 }, style = Thin
-cc e4d96a13d6a8c7625e49d3545f6076d58152f3b5eb43fae65f0d407d1d34f96c # shrinks to dims = Dimensions { w: 1, h: 1 }, style = Thin
-cc b5f0d7cb409896bd6692544c7c1f781174075c287d3b7a3b9dc73526ea489484 # shrinks to dims = Dimensions { w: 1, h: 1 }, style = Thin
-cc 103b62b7c29c22adcbc23153638d3b37bad57aeec685d1eab38c49d0deed937f # shrinks to dims = Dimensions { w: 0, h: 1 }, style = Thin
-cc 24c3858a543b0d8ff4966517040ec8c183ed311688d6863fd13facb5cdad7aa0 # shrinks to dims = Dimensions { w: 1, h: 1 }, style = Thin
-cc 70a53a8b771937976a08a72d870b355a0995cc0251f45de4393c37a56a789b83 # shrinks to dims = Dimensions { w: 0, h: 0 }, style = Thin
diff --git a/proptest-regressions/display/viewport.txt b/proptest-regressions/display/viewport.txt
deleted file mode 100644
index e38056d975ff..000000000000
--- a/proptest-regressions/display/viewport.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-# Seeds for failure cases proptest has generated in the past. It is
-# automatically read and these particular cases re-run before any
-# novel cases are generated.
-#
-# It is recommended to check this file in to source control so that
-# everyone who runs the test benefits from these saved cases.
-cc b84a5a6dbba5cfc69329a119d9e20328c0372e0db2b72e5d71d971e3f13f8749 # shrinks to pos = Position { x: 0, y: 0 }, outer = BoundingBox { dimensions: Dimensions { w: 0, h: 0 }, position: Position { x: 0, y: 0 } }
diff --git a/proptest-regressions/types/entity_map.txt b/proptest-regressions/types/entity_map.txt
deleted file mode 100644
index 68be5752f4e0..000000000000
--- a/proptest-regressions/types/entity_map.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-# Seeds for failure cases proptest has generated in the past. It is
-# automatically read and these particular cases re-run before any
-# novel cases are generated.
-#
-# It is recommended to check this file in to source control so that
-# everyone who runs the test benefits from these saved cases.
-cc 16afe2473971397314ffa77acf7bad62f0c40bc3f591aff7aa9193c29e5a0921 # shrinks to items = [(Position { x: 92, y: 60 }, ""), (Position { x: 92, y: 60 }, "")]
-cc 3a68a382c3bb8fdf60ea150a369abbdd45859e0c54cd6a4f7c75937a6c783b98 # shrinks to mut em = EntityMap { by_position: {Position { x: 25, y: 33 }: [1]}, by_id: {1: TestEntity { position: Position { x: 25, y: 33 }, name: "" }}, last_id: 1 }, ent = TestEntity { position: Position { x: 25, y: 33 }, name: "" }, new_position = Position { x: 0, y: 0 }
-cc ffd7181e1c0343ab4c2ac92990f068d24c8663158c1c0a9526cd9edc470f950a # shrinks to mut em = EntityMap { by_position: {Position { x: 64, y: 58 }: [1]}, by_id: {1: TestEntity { position: Position { x: 64, y: 58 }, name: "" }}, last_id: 1 }, ent = TestEntity { position: Position { x: 0, y: 0 }, name: "" }, new_position = Position { x: 64, y: 58 }
diff --git a/proptest-regressions/types/mod.txt b/proptest-regressions/types/mod.txt
deleted file mode 100644
index 276466965c44..000000000000
--- a/proptest-regressions/types/mod.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-# Seeds for failure cases proptest has generated in the past. It is
-# automatically read and these particular cases re-run before any
-# novel cases are generated.
-#
-# It is recommended to check this file in to source control so that
-# everyone who runs the test benefits from these saved cases.
-cc a51cf37623f0e4024f4ba1450195be296d9b9e8ae954dbbf997ce5b57cd26792 # shrinks to a = Position { x: 44, y: 25 }, b = Position { x: 0, y: 25 }, c = Position { x: 0, y: 0 }
-cc 0816b9348c53ef8c8328f0ea72d5ebef215f6764b1cbbd3c5db958e214c5fa3a # shrinks to pos = Position { x: 0, y: 0 }, dir = Down
diff --git a/rustfmt.toml b/rustfmt.toml
deleted file mode 100644
index df99c69198f5..000000000000
--- a/rustfmt.toml
+++ /dev/null
@@ -1 +0,0 @@
-max_width = 80
diff --git a/src/cli.yml b/src/cli.yml
deleted file mode 100644
index 4b2e94e57b0e..000000000000
--- a/src/cli.yml
+++ /dev/null
@@ -1,46 +0,0 @@
-name: xanthous
-version: "0.0"
-author: Griffin Smith <root@gws.fyi>
-about: hey, it's a terminal game
-args:
-  - config:
-      short: c
-      long: config
-      value_name: FILE
-      help: Sets a custom config file
-      takes_value: true
-subcommands:
-  - info:
-      about: Writes debug information to the terminal and exits
-  - generate-level:
-      about: Generate a level and print it to the screen
-      args:
-      - generator:
-          long: generator
-          value_name: GEN
-          help: Select which generator to use
-          takes_value: true
-      - width:
-          long: width
-          short: w
-          value_name: WIDTH
-          takes_value: true
-      - height:
-          long: height
-          short: h
-          value_name: HEIGHT
-          takes_value: true
-      - start-alive-chance:
-          long: start-alive-chance
-          takes_value: true
-      - birth_limit:
-          long: birth-limit
-          takes_value: true
-      - death_limit:
-          long: death-limit
-          takes_value: true
-      - steps:
-          long: steps
-          short: s
-          value_name: STEPS
-          takes_value: true
diff --git a/src/description.rs b/src/description.rs
deleted file mode 100644
index 48c98d76e051..000000000000
--- a/src/description.rs
+++ /dev/null
@@ -1,93 +0,0 @@
-use crate::entities::Describe;
-
-pub fn list_to_sentence(lst: &[String]) -> String {
-    let mut buf = String::with_capacity(
-        lst.iter()
-            .map(|e| e.len() + 2usize /* ", " */)
-            .sum::<usize>()
-            + if lst.len() >= 3 {
-                3usize /* "and" */
-            } else {
-                0usize
-            },
-    );
-
-    match lst.len() {
-        0 => {}
-        1 => buf.push_str(&lst[0]),
-        2 => {
-            buf.push_str(&lst[0]);
-            buf.push_str(" and ");
-            buf.push_str(&lst[1]);
-        }
-        _ => {
-            for desc in &lst[..lst.len() - 1] {
-                buf.push_str(desc);
-                buf.push_str(", ");
-            }
-            buf.push_str("and ");
-            buf.push_str(&lst[lst.len() - 1]);
-        }
-    }
-
-    buf
-}
-
-pub fn describe_list<A: Describe>(lst: &[A]) -> String {
-    list_to_sentence(
-        &lst.iter().map(|e| e.description()).collect::<Vec<String>>(),
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use proptest::prelude::*;
-    use proptest_derive::Arbitrary;
-
-    #[derive(Debug, Arbitrary)]
-    struct Description(String);
-
-    impl Describe for Description {
-        fn description(&self) -> String {
-            self.0.clone()
-        }
-    }
-
-    proptest! {
-        #[test]
-        fn test_describe_list_includes_all_descriptions(
-            descriptions: Vec<Description>
-        ) {
-            let res = describe_list(&descriptions);
-            for Description(desc) in descriptions {
-                assert!(res.contains(&desc));
-            }
-        }
-    }
-
-    #[test]
-    fn test_describe_list() {
-        assert_eq!(
-            describe_list(&[Description("one".to_string())]),
-            "one".to_string()
-        );
-
-        assert_eq!(
-            describe_list(&[
-                Description("one".to_string()),
-                Description("two".to_string())
-            ]),
-            "one and two".to_string()
-        );
-
-        assert_eq!(
-            describe_list(&[
-                Description("one".to_string()),
-                Description("two".to_string()),
-                Description("three".to_string())
-            ]),
-            "one, two, and three".to_string()
-        );
-    }
-}
diff --git a/src/display/color.rs b/src/display/color.rs
deleted file mode 100644
index afe0039998b8..000000000000
--- a/src/display/color.rs
+++ /dev/null
@@ -1,163 +0,0 @@
-use serde::de::{self, Unexpected, Visitor};
-use std::fmt;
-use std::marker::PhantomData;
-use termion::color;
-
-#[derive(Debug)]
-pub struct Color(Box<dyn color::Color>);
-
-unsafe impl Sync for Color {}
-unsafe impl Send for Color {}
-
-impl Color {
-    pub fn new<C: color::Color + 'static>(c: C) -> Self {
-        Color(Box::new(c))
-    }
-}
-
-impl PartialEq for Color {
-    fn eq(&self, other: &Self) -> bool {
-        format!("{}{}", color::Fg(self), color::Bg(self))
-            == format!("{}{}", color::Fg(other), color::Bg(other))
-    }
-}
-
-impl Eq for Color {}
-
-impl color::Color for Color {
-    fn write_fg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.0.write_fg(f)
-    }
-
-    fn write_bg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.0.write_bg(f)
-    }
-}
-
-impl<'a> color::Color for &'a Color {
-    fn write_fg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.0.write_fg(f)
-    }
-
-    fn write_bg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.0.write_bg(f)
-    }
-}
-
-impl Default for Color {
-    fn default() -> Self {
-        Color::new(color::Reset)
-    }
-}
-
-pub struct ColorVisitor {
-    marker: PhantomData<fn() -> Color>,
-}
-
-impl ColorVisitor {
-    fn new() -> Self {
-        ColorVisitor {
-            marker: PhantomData,
-        }
-    }
-}
-
-impl<'de> Visitor<'de> for ColorVisitor {
-    type Value = Color;
-
-    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-        formatter.write_str("A color")
-    }
-
-    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
-    where
-        E: de::Error,
-    {
-        match v.to_lowercase().as_ref() {
-            "black" => Ok(Color(Box::new(color::Black))),
-            "blue" => Ok(Color(Box::new(color::Blue))),
-            "cyan" => Ok(Color(Box::new(color::Cyan))),
-            "green" => Ok(Color(Box::new(color::Green))),
-            "light black" | "light_black" => {
-                Ok(Color(Box::new(color::LightBlack)))
-            }
-            "light blue" | "light_blue" => {
-                Ok(Color(Box::new(color::LightBlue)))
-            }
-            "light cyan" | "light_cyan" => {
-                Ok(Color(Box::new(color::LightCyan)))
-            }
-            "light green" | "light_green" => {
-                Ok(Color(Box::new(color::LightGreen)))
-            }
-            "light magenta" | "light_magenta" => {
-                Ok(Color(Box::new(color::LightMagenta)))
-            }
-            "light red" | "light_red" => Ok(Color(Box::new(color::LightRed))),
-            "light white" | "light_white" => {
-                Ok(Color(Box::new(color::LightWhite)))
-            }
-            "light yellow" | "light_yellow" => {
-                Ok(Color(Box::new(color::LightYellow)))
-            }
-            "magenta" => Ok(Color(Box::new(color::Magenta))),
-            "red" => Ok(Color(Box::new(color::Red))),
-            "white" => Ok(Color(Box::new(color::White))),
-            "yellow" => Ok(Color(Box::new(color::Yellow))),
-            _ => Err(de::Error::invalid_value(
-                Unexpected::Str(v),
-                &"a valid color",
-            )),
-        }
-    }
-
-    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
-    where
-        A: de::MapAccess<'de>,
-    {
-        let mut red = None;
-        let mut green = None;
-        let mut blue = None;
-        while let Some((k, v)) = map.next_entry()? {
-            match k {
-                "red" => {
-                    red = Some(v);
-                }
-                "green" => {
-                    green = Some(v);
-                }
-                "blue" => {
-                    blue = Some(v);
-                }
-                _ => {
-                    return Err(de::Error::unknown_field(
-                        k,
-                        &["red", "green", "blue"],
-                    ));
-                }
-            }
-        }
-
-        match (red, green, blue) {
-            (Some(r), Some(g), Some(b)) => {
-                Ok(Color(Box::new(color::Rgb(r, g, b))))
-            }
-            (None, _, _) => Err(de::Error::missing_field("red")),
-            (_, None, _) => Err(de::Error::missing_field("green")),
-            (_, _, None) => Err(de::Error::missing_field("blue")),
-        }
-    }
-
-    fn visit_u8<E: de::Error>(self, v: u8) -> Result<Self::Value, E> {
-        Ok(Color(Box::new(color::AnsiValue(v))))
-    }
-}
-
-impl<'de> serde::Deserialize<'de> for Color {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
-    where
-        D: serde::Deserializer<'de>,
-    {
-        deserializer.deserialize_any(ColorVisitor::new())
-    }
-}
diff --git a/src/display/draw_box.rs b/src/display/draw_box.rs
deleted file mode 100644
index e4d34a7acda9..000000000000
--- a/src/display/draw_box.rs
+++ /dev/null
@@ -1,274 +0,0 @@
-use crate::display::utils::clone_times;
-use crate::display::utils::times;
-use crate::types::pos;
-use crate::types::BoundingBox;
-use crate::types::Dimensions;
-use crate::types::Neighbors;
-use itertools::Itertools;
-use proptest::prelude::Arbitrary;
-use proptest::strategy;
-use proptest_derive::Arbitrary;
-use std::io::{self, Write};
-
-// Box Drawing
-//  	    0 	1 	2 	3 	4 	5 	6 	7 	8 	9 	A 	B 	C 	D 	E 	F
-// U+250x 	โ”€ 	โ” 	โ”‚ 	โ”ƒ 	โ”„ 	โ”… 	โ”† 	โ”‡ 	โ”ˆ 	โ”‰ 	โ”Š 	โ”‹ 	โ”Œ 	โ” 	โ”Ž 	โ”
-// U+251x 	โ” 	โ”‘ 	โ”’ 	โ”“ 	โ”” 	โ”• 	โ”– 	โ”— 	โ”˜ 	โ”™ 	โ”š 	โ”› 	โ”œ 	โ” 	โ”ž 	โ”Ÿ
-// U+252x 	โ”  	โ”ก 	โ”ข 	โ”ฃ 	โ”ค 	โ”ฅ 	โ”ฆ 	โ”ง 	โ”จ 	โ”ฉ 	โ”ช 	โ”ซ 	โ”ฌ 	โ”ญ 	โ”ฎ 	โ”ฏ
-// U+253x 	โ”ฐ 	โ”ฑ 	โ”ฒ 	โ”ณ 	โ”ด 	โ”ต 	โ”ถ 	โ”ท 	โ”ธ 	โ”น 	โ”บ 	โ”ป 	โ”ผ 	โ”ฝ 	โ”พ 	โ”ฟ
-// U+254x 	โ•€ 	โ• 	โ•‚ 	โ•ƒ 	โ•„ 	โ•… 	โ•† 	โ•‡ 	โ•ˆ 	โ•‰ 	โ•Š 	โ•‹ 	โ•Œ 	โ• 	โ•Ž 	โ•
-// U+255x 	โ• 	โ•‘ 	โ•’ 	โ•“ 	โ•” 	โ•• 	โ•– 	โ•— 	โ•˜ 	โ•™ 	โ•š 	โ•› 	โ•œ 	โ• 	โ•ž 	โ•Ÿ
-// U+256x 	โ•  	โ•ก 	โ•ข 	โ•ฃ 	โ•ค 	โ•ฅ 	โ•ฆ 	โ•ง 	โ•จ 	โ•ฉ 	โ•ช 	โ•ซ 	โ•ฌ 	โ•ญ 	โ•ฎ 	โ•ฏ
-// U+257x 	โ•ฐ 	โ•ฑ 	โ•ฒ 	โ•ณ 	โ•ด 	โ•ต 	โ•ถ 	โ•ท 	โ•ธ 	โ•น 	โ•บ 	โ•ป 	โ•ผ 	โ•ฝ 	โ•พ 	โ•ฟ
-
-static BOX: char = 'โ˜';
-
-static BOX_CHARS: [[char; 16]; 8] = [
-    // 0
-    [
-        // 0    1    2    3    4    5    6    7    8    9
-        'โ”€', 'โ”', 'โ”‚', 'โ”ƒ', 'โ”„', 'โ”…', 'โ”†', 'โ”‡', 'โ”ˆ', 'โ”‰',
-        // 10
-        'โ”Š', 'โ”‹', 'โ”Œ', 'โ”', 'โ”Ž', 'โ”',
-    ],
-    // 1
-    [
-        // 0    1    2    3    4    5    6    7    8    9
-        'โ”', 'โ”‘', 'โ”’', 'โ”“', 'โ””', 'โ”•', 'โ”–', 'โ”—', 'โ”˜', 'โ”™',
-        'โ”š', 'โ”›', 'โ”œ', 'โ”', 'โ”ž', 'โ”Ÿ',
-    ],
-    // 2
-    [
-        // 0    1    2    3    4    5    6    7    8    9
-        'โ” ', 'โ”ก', 'โ”ข', 'โ”ฃ', 'โ”ค', 'โ”ฅ', 'โ”ฆ', 'โ”ง', 'โ”จ', 'โ”ฉ',
-        'โ”ช', 'โ”ซ', 'โ”ฌ', 'โ”ญ', 'โ”ฎ', 'โ”ฏ',
-    ],
-    // 3
-    [
-        // 0    1    2    3    4    5    6    7    8    9
-        'โ”ฐ', 'โ”ฑ', 'โ”ฒ', 'โ”ณ', 'โ”ด', 'โ”ต', 'โ”ถ', 'โ”ท', 'โ”ธ', 'โ”น',
-        'โ”บ', 'โ”ป', 'โ”ผ', 'โ”ฝ', 'โ”พ', 'โ”ฟ',
-    ],
-    // 4
-    [
-        // 0    1    2    3    4    5    6    7    8    9
-        'โ•€', 'โ•', 'โ•‚', 'โ•ƒ', 'โ•„', 'โ•…', 'โ•†', 'โ•‡', 'โ•ˆ', 'โ•‰',
-        'โ•Š', 'โ•‹', 'โ•Œ', 'โ•', 'โ•Ž', 'โ•',
-    ],
-    // 5
-    [
-        // 0    1    2    3    4    5    6    7    8    9
-        'โ•', 'โ•‘', 'โ•’', 'โ•“', 'โ•”', 'โ••', 'โ•–', 'โ•—', 'โ•˜', 'โ•™',
-        'โ•š', 'โ•›', 'โ•œ', 'โ•', 'โ•ž', 'โ•Ÿ',
-    ],
-    // 6
-    [
-        // 0    1    2    3    4    5    6    7    8    9
-        'โ• ', 'โ•ก', 'โ•ข', 'โ•ฃ', 'โ•ค', 'โ•ฅ', 'โ•ฆ', 'โ•ง', 'โ•จ', 'โ•ฉ',
-        'โ•ช', 'โ•ซ', 'โ•ฌ', 'โ•ญ', 'โ•ฎ', 'โ•ฏ',
-    ],
-    // 7
-    [
-        // 0    1    2    3    4    5    6    7    8    9
-        'โ•ฐ', 'โ•ฑ', 'โ•ฒ', 'โ•ณ', 'โ•ด', 'โ•ต', 'โ•ถ', 'โ•ท', 'โ•ธ', 'โ•น',
-        'โ•บ', 'โ•ป', 'โ•ผ', 'โ•ฝ', 'โ•พ', 'โ•ฟ',
-    ],
-];
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum BoxStyle {
-    Thin,
-    Thick,
-    Dotted,
-    ThickDotted,
-    Dashed,
-    ThickDashed,
-    Double,
-}
-
-impl Arbitrary for BoxStyle {
-    type Parameters = ();
-    type Strategy = strategy::Just<Self>;
-    fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
-        // TODO
-        strategy::Just(BoxStyle::Thin)
-    }
-}
-
-pub trait Stylable {
-    fn style(&self, style: BoxStyle) -> char;
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary)]
-enum Corner {
-    TopRight,
-    TopLeft,
-    BottomRight,
-    BottomLeft,
-}
-
-impl Stylable for Corner {
-    fn style(&self, style: BoxStyle) -> char {
-        use BoxStyle::*;
-        use Corner::*;
-
-        match (self, style) {
-            (TopRight, Thin) => BOX_CHARS[1][0],
-            (TopLeft, Thin) => BOX_CHARS[0][12],
-            (BottomRight, Thin) => BOX_CHARS[1][8],
-            (BottomLeft, Thin) => BOX_CHARS[1][4],
-            _ => unimplemented!(),
-        }
-    }
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary)]
-enum Line {
-    H,
-    V,
-}
-
-impl Stylable for Line {
-    fn style(&self, style: BoxStyle) -> char {
-        use BoxStyle::*;
-        use Line::*;
-        match (self, style) {
-            (H, Thin) => BOX_CHARS[0][0],
-            (V, Thin) => BOX_CHARS[0][2],
-            _ => unimplemented!(),
-        }
-    }
-}
-
-impl Stylable for Neighbors<Option<BoxStyle>> {
-    fn style(&self, _style: BoxStyle) -> char {
-        use BoxStyle::*;
-        match (self.left, self.right, self.top, self.bottom) {
-            (None, None, None, None) => BOX,
-            (Some(Thin), None, None, None) => BOX_CHARS[7][4],
-            (None, Some(Thin), None, None) => BOX_CHARS[7][6],
-            (None, None, Some(Thin), None) => BOX_CHARS[7][5],
-            (None, None, None, Some(Thin)) => BOX_CHARS[7][7],
-            (Some(Thin), Some(Thin), None, None) => Line::H.style(Thin),
-            (Some(Thin), None, Some(Thin), None) => {
-                Corner::BottomRight.style(Thin)
-            }
-            (Some(Thin), None, None, Some(Thin)) => {
-                Corner::TopRight.style(Thin)
-            }
-            (None, Some(Thin), Some(Thin), None) => {
-                Corner::BottomLeft.style(Thin)
-            }
-            (None, Some(Thin), None, Some(Thin)) => Corner::TopLeft.style(Thin),
-            (None, None, Some(Thin), Some(Thin)) => Line::V.style(Thin),
-            (None, Some(Thin), Some(Thin), Some(Thin)) => BOX_CHARS[1][12],
-            (Some(Thin), None, Some(Thin), Some(Thin)) => BOX_CHARS[2][4],
-            (Some(Thin), Some(Thin), None, Some(Thin)) => BOX_CHARS[2][12],
-            (Some(Thin), Some(Thin), Some(Thin), None) => BOX_CHARS[3][4],
-            (Some(Thin), Some(Thin), Some(Thin), Some(Thin)) => {
-                BOX_CHARS[3][12]
-            }
-            neighs => panic!("unimplemented: {:?}", neighs),
-        }
-    }
-}
-
-#[must_use]
-pub fn make_box(style: BoxStyle, dims: Dimensions) -> String {
-    if dims.h == 0 || dims.w == 0 {
-        "".to_string()
-    } else if dims.h == 1 && dims.w == 1 {
-        BOX.to_string()
-    } else if dims.h == 1 {
-        times(Line::H.style(style), dims.w)
-    } else if dims.w == 1 {
-        (0..dims.h).map(|_| Line::V.style(style)).join("\n\r")
-    } else {
-        let h_line: String = times(Line::H.style(style), dims.w - 2);
-        let v_line = Line::V.style(style);
-        let v_walls: String = clone_times(
-            format!(
-                "{}{}{}\n\r",
-                v_line,
-                times::<_, String>(' ', dims.w - 2),
-                v_line
-            ),
-            dims.h - 2,
-        );
-
-        format!(
-            "{}{}{}\n\r{}{}{}{}",
-            Corner::TopLeft.style(style),
-            h_line,
-            Corner::TopRight.style(style),
-            v_walls,
-            Corner::BottomLeft.style(style),
-            h_line,
-            Corner::BottomRight.style(style),
-        )
-    }
-}
-
-/// Draw the box described by the given BoundingBox's position and dimensions to
-/// the given output, with the given style
-pub fn draw_box<W: Write>(
-    out: &mut W,
-    bbox: BoundingBox,
-    style: BoxStyle,
-) -> io::Result<()> {
-    let box_str = make_box(style, bbox.dimensions);
-    if bbox.position.x == 0 {
-        write!(out, "{}{}", bbox.position.cursor_goto(), box_str)?;
-    } else {
-        for (i, line) in box_str.split("\n\r").enumerate() {
-            debug!("line: {:?}!", line);
-            write!(
-                out,
-                "{}{}",
-                (bbox.position + pos(0, i as i16)).cursor_goto(),
-                line
-            )?;
-        }
-    }
-    Ok(())
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use proptest::prelude::*;
-
-    #[test]
-    fn make_thin_box() {
-        let res = make_box(BoxStyle::Thin, Dimensions { w: 10, h: 10 });
-        assert_eq!(
-            res,
-            "โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
-\rโ”‚        โ”‚
-\rโ”‚        โ”‚
-\rโ”‚        โ”‚
-\rโ”‚        โ”‚
-\rโ”‚        โ”‚
-\rโ”‚        โ”‚
-\rโ”‚        โ”‚
-\rโ”‚        โ”‚
-\rโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜"
-        );
-    }
-
-    proptest! {
-        #[test]
-        fn box_has_height_lines(dims: Dimensions, style: BoxStyle) {
-            let res = make_box(style, dims);
-            prop_assume!((dims.w > 0 && dims.h > 0));
-            assert_eq!(res.split("\n\r").count(), dims.h as usize);
-        }
-
-        #[test]
-        fn box_lines_have_width_length(dims: Dimensions, style: BoxStyle) {
-            let res = make_box(style, dims);
-            prop_assume!(dims.w == 0 && dims.h == 0 || (dims.w > 0 && dims.h > 0));
-            assert!(res.split("\n\r").all(|l| l.chars().count() == dims.w as usize));
-        }
-    }
-}
diff --git a/src/display/mod.rs b/src/display/mod.rs
deleted file mode 100644
index 6e37a03d8c55..000000000000
--- a/src/display/mod.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-pub mod color;
-pub mod draw_box;
-pub mod utils;
-pub mod viewport;
-use crate::entities::entity::Entity;
-use crate::types::Neighbors;
-use crate::types::Positioned;
-pub use draw_box::{make_box, BoxStyle};
-use std::io::{self, Write};
-use termion::{clear, cursor, style};
-pub use viewport::Viewport;
-
-pub fn clear<T: Write>(out: &mut T) -> io::Result<()> {
-    write!(out, "{}{}{}", clear::All, style::Reset, cursor::Goto(1, 1))
-}
-
-pub trait Draw: Positioned {
-    /// Draw this entity, assuming the character is already at the correct
-    /// position
-    fn do_draw(&self, out: &mut dyn Write) -> io::Result<()>;
-}
-
-impl<T: Draw> Draw for &T {
-    fn do_draw(&self, out: &mut dyn Write) -> io::Result<()> {
-        (**self).do_draw(out)
-    }
-}
-
-impl<T: Draw> Draw for Box<T> {
-    fn do_draw(&self, out: &mut dyn Write) -> io::Result<()> {
-        (**self).do_draw(out)
-    }
-}
-
-pub trait DrawWithNeighbors: Positioned {
-    #[allow(clippy::borrowed_box)]
-    fn do_draw_with_neighbors<'a, 'b>(
-        &'a self,
-        out: &'b mut dyn Write,
-        neighbors: &'a Neighbors<Vec<&'a Box<dyn Entity>>>,
-    ) -> io::Result<()>;
-}
-
-impl<T: Draw> DrawWithNeighbors for T {
-    fn do_draw_with_neighbors<'a, 'b>(
-        &'a self,
-        out: &'b mut dyn Write,
-        _neighbors: &'a Neighbors<Vec<&'a Box<dyn Entity>>>,
-    ) -> io::Result<()> {
-        self.do_draw(out)
-    }
-}
diff --git a/src/display/utils.rs b/src/display/utils.rs
deleted file mode 100644
index acd4416cb884..000000000000
--- a/src/display/utils.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-use std::iter::FromIterator;
-
-pub fn times<A: Copy, B: FromIterator<A>>(elem: A, n: u16) -> B {
-    (0..n).map(|_| elem).collect()
-}
-
-pub fn clone_times<A: Clone, B: FromIterator<A>>(elem: A, n: u16) -> B {
-    (0..n).map(|_| elem.clone()).collect()
-}
diff --git a/src/display/viewport.rs b/src/display/viewport.rs
deleted file mode 100644
index c44316cdaad5..000000000000
--- a/src/display/viewport.rs
+++ /dev/null
@@ -1,303 +0,0 @@
-use super::BoxStyle;
-use super::DrawWithNeighbors;
-use crate::display::draw_box::draw_box;
-use crate::display::utils::clone_times;
-use crate::entities::entity::Entity;
-use crate::types::menu::MenuInfo;
-use crate::types::Neighbors;
-use crate::types::{pos, BoundingBox, Direction, Position, Positioned};
-use std::fmt::{self, Debug};
-use std::io::{self, Write};
-
-pub enum CursorState {
-    Game,
-    Prompt(Position),
-}
-
-impl Default for CursorState {
-    fn default() -> Self {
-        CursorState::Game
-    }
-}
-
-pub struct Viewport<W> {
-    /// The box describing the visible part of the viewport.
-    ///
-    /// Generally the size of the terminal, and positioned at 0, 0
-    pub outer: BoundingBox,
-
-    /// The box describing the game part of the viewport.
-    pub game: BoundingBox,
-
-    /// The box describing the inner part of the viewport
-    ///
-    /// Its position is relative to `outer.inner()`, and its size should
-    /// generally not be smaller than outer
-    pub inner: BoundingBox,
-
-    /// The actual screen that the viewport writes to
-    pub out: W,
-
-    cursor_state: CursorState,
-
-    /// Reset the cursor back to this position after every draw
-    pub game_cursor_position: Position,
-}
-
-impl<W> Viewport<W> {
-    pub fn new(outer: BoundingBox, inner: BoundingBox, out: W) -> Self {
-        Viewport {
-            outer,
-            inner,
-            out,
-            game: outer.move_tr_corner(Position { x: 0, y: 1 }),
-            cursor_state: Default::default(),
-            game_cursor_position: pos(0, 0),
-        }
-    }
-
-    /// Returns true if the (inner-relative) position of the given entity is
-    /// visible within this viewport
-    pub fn visible<E: Positioned>(&self, ent: &E) -> bool {
-        self.on_screen(ent.position()).within(self.game.inner())
-    }
-
-    /// Convert the given inner-relative position to one on the actual screen
-    fn on_screen(&self, pos: Position) -> Position {
-        pos + self.inner.position + self.game.inner().position
-    }
-}
-
-impl<W> Debug for Viewport<W> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "Viewport {{ outer: {:?}, inner: {:?}, out: <OUT> }}",
-            self.outer, self.inner
-        )
-    }
-}
-
-impl<W: Write> Viewport<W> {
-    /// Draw the given entity to the viewport at its position, if visible
-    #[allow(clippy::borrowed_box)]
-    pub fn draw<T: DrawWithNeighbors>(
-        &mut self,
-        entity: &T,
-        neighbors: &Neighbors<Vec<&Box<dyn Entity>>>,
-    ) -> io::Result<()> {
-        if !self.visible(entity) {
-            return Ok(());
-        }
-        self.cursor_goto(entity.position())?;
-        entity.do_draw_with_neighbors(self, neighbors)?;
-        self.reset_cursor()
-    }
-
-    fn reset_cursor(&mut self) -> io::Result<()> {
-        self.cursor_goto(self.game_cursor_position)
-    }
-
-    /// Move the cursor to the given inner-relative position
-    pub fn cursor_goto(&mut self, pos: Position) -> io::Result<()> {
-        write!(self, "{}", self.on_screen(pos).cursor_goto())
-    }
-
-    /// Clear whatever single character is drawn at the given inner-relative
-    /// position, if visible
-    pub fn clear(&mut self, pos: Position) -> io::Result<()> {
-        write!(self, "{} ", self.on_screen(pos).cursor_goto(),)?;
-        self.reset_cursor()
-    }
-
-    /// Initialize this viewport by drawing its outer box to the screen
-    pub fn init(&mut self) -> io::Result<()> {
-        draw_box(self, self.game, BoxStyle::Thin)
-    }
-
-    /// Write a message to the message area on the screen
-    ///
-    /// Will overwrite any message already present, and if the given message is
-    /// longer than the screen will truncate. This means callers should handle
-    /// message buffering and ellipsisization
-    pub fn write_message(&mut self, msg: &str) -> io::Result<usize> {
-        let msg_to_write = if msg.len() <= self.outer.dimensions.w as usize {
-            msg
-        } else {
-            &msg[0..self.outer.dimensions.w as usize]
-        };
-        write!(
-            self,
-            "{}{}{}",
-            self.outer.position.cursor_goto(),
-            msg_to_write,
-            clone_times::<_, String>(
-                " ".to_string(),
-                self.outer.dimensions.w - msg.len() as u16
-            ),
-        )?;
-        self.reset_cursor()?;
-        Ok(msg_to_write.len())
-    }
-
-    pub fn clear_message(&mut self) -> io::Result<()> {
-        write!(
-            self,
-            "{}{}",
-            self.outer.position.cursor_goto(),
-            clone_times::<_, String>(
-                " ".to_string(),
-                self.outer.dimensions.w as u16
-            )
-        )?;
-        self.reset_cursor()
-    }
-
-    /// Write a prompt requesting text input to the message area on the screen.
-    ///
-    /// Will overwrite any message already present, and if the given message is
-    /// longer than the screen will truncate. This means callers should handle
-    /// message buffering and ellipsisization
-    pub fn write_prompt<'a, 'b>(&'a mut self, msg: &'b str) -> io::Result<()> {
-        let len = self.write_message(msg)? + 1;
-        let pos = self.outer.position + pos(len as i16, 0);
-        self.cursor_state = CursorState::Prompt(pos);
-        write!(self, "{}", pos.cursor_goto())?;
-        self.flush()
-    }
-
-    pub fn push_prompt_chr(&mut self, chr: char) -> io::Result<()> {
-        if let CursorState::Prompt(pos) = self.cursor_state {
-            write!(self, "{}", chr)?;
-            self.cursor_state = CursorState::Prompt(pos + Direction::Right);
-        }
-        Ok(())
-    }
-
-    pub fn pop_prompt_chr(&mut self) -> io::Result<()> {
-        if let CursorState::Prompt(pos) = self.cursor_state {
-            let new_pos = pos + Direction::Left;
-            write!(
-                self,
-                "{} {}",
-                new_pos.cursor_goto(),
-                new_pos.cursor_goto()
-            )?;
-            self.cursor_state = CursorState::Prompt(new_pos);
-        }
-        Ok(())
-    }
-
-    pub fn clear_prompt(&mut self) -> io::Result<()> {
-        self.clear_message()?;
-        self.cursor_state = CursorState::Game;
-        Ok(())
-    }
-
-    pub fn write_menu(&mut self, menu: &MenuInfo) -> io::Result<()> {
-        let menu_dims = menu.dimensions();
-
-        // TODO: check if the menu is too big
-
-        let menu_position = self.game.position + pos(1, 1);
-
-        let menu_box = BoundingBox {
-            dimensions: menu_dims,
-            position: menu_position,
-        };
-
-        debug!("writing menu at: {:?}", menu_box);
-
-        draw_box(self, menu_box, BoxStyle::Thin)?;
-
-        write!(
-            self,
-            "{}{}",
-            (menu_position + pos(2, 2)).cursor_goto(),
-            menu.prompt
-        )?;
-
-        for (idx, option) in menu.options.iter().enumerate() {
-            write!(
-                self,
-                "{}{}",
-                (menu_position + pos(2, 4 + idx as i16)).cursor_goto(),
-                option
-            )?;
-        }
-
-        Ok(())
-    }
-}
-
-impl<W> Positioned for Viewport<W> {
-    fn position(&self) -> Position {
-        self.outer.position
-    }
-}
-
-impl<W: Write> Write for Viewport<W> {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        self.out.write(buf)
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        self.out.flush()
-    }
-
-    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
-        self.out.write_all(buf)
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::types::Dimensions;
-
-    #[test]
-    fn test_visible() {
-        assert!(Viewport::new(
-            BoundingBox::at_origin(Dimensions { w: 10, h: 10 }),
-            BoundingBox {
-                position: Position { x: -10, y: -10 },
-                dimensions: Dimensions { w: 15, h: 15 },
-            },
-            ()
-        )
-        .visible(&Position { x: 13, y: 13 }));
-
-        assert!(!Viewport::new(
-            BoundingBox::at_origin(Dimensions { w: 10, h: 10 }),
-            BoundingBox {
-                position: Position { x: -10, y: -10 },
-                dimensions: Dimensions { w: 15, h: 15 },
-            },
-            (),
-        )
-        .visible(&Position { x: 1, y: 1 }));
-    }
-
-    #[test]
-    fn test_write_menu() {
-        let buf: Vec<u8> = Vec::new();
-
-        let mut viewport = Viewport::new(
-            BoundingBox::at_origin(Dimensions::default()),
-            BoundingBox::at_origin(Dimensions::default()),
-            buf,
-        );
-
-        let menu = MenuInfo::new(
-            "Test menu".to_string(),
-            vec!["option 1".to_string(), "option 2".to_string()],
-        );
-
-        viewport.write_menu(&menu).unwrap();
-
-        let res = std::str::from_utf8(&viewport.out).unwrap();
-        assert!(res.contains("Test menu"));
-        assert!(res.contains("option 1"));
-        assert!(res.contains("option 2"));
-    }
-}
diff --git a/src/entities/character.rs b/src/entities/character.rs
deleted file mode 100644
index 3e8336b129ff..000000000000
--- a/src/entities/character.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-use crate::display;
-use crate::entities::item::Item;
-use crate::types::{Position, Speed};
-use std::io::{self, Write};
-
-const DEFAULT_SPEED: Speed = Speed(100);
-
-entity! {
-    pub struct Character {
-        pub o_name: Option<String>,
-        pub inventory: Vec<Box<Item>>,
-    }
-}
-
-static_description!(Character, "yourself");
-
-impl Character {
-    pub fn new() -> Character {
-        Character {
-            id: None,
-            position: Position { x: 0, y: 0 },
-            o_name: None,
-            inventory: Vec::new(),
-        }
-    }
-
-    pub fn speed(&self) -> Speed {
-        Speed(100)
-    }
-
-    pub fn damage(&self) -> u16 {
-        // TODO
-        1
-    }
-
-    pub fn name(&self) -> &str {
-        self.o_name
-            .as_ref()
-            .expect("Character name not initialized")
-    }
-
-    pub fn set_name(&mut self, name: String) {
-        self.o_name = Some(name);
-    }
-}
-
-impl display::Draw for Character {
-    fn do_draw(&self, out: &mut dyn Write) -> io::Result<()> {
-        write!(out, "@")
-    }
-}
diff --git a/src/entities/creature.rs b/src/entities/creature.rs
deleted file mode 100644
index 20071c1d88eb..000000000000
--- a/src/entities/creature.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-use crate::display;
-use crate::entities::raws::CreatureType;
-use crate::entities::raws::EntityRaw;
-use crate::entities::{raw, Describe, EntityID};
-use crate::types::Position;
-use std::io::{self, Write};
-
-#[derive(Debug, Clone)]
-pub struct Creature {
-    pub id: Option<EntityID>,
-    pub typ: &'static CreatureType<'static>,
-    pub position: Position,
-    pub hitpoints: u16,
-}
-
-impl Creature {
-    pub fn new_from_raw(name: &'static str, position: Position) -> Self {
-        match raw(name) {
-            EntityRaw::Creature(typ) => Self::new_with_type(typ, position),
-            _ => panic!("Invalid raw type for {:?}, expected Creature", name),
-        }
-    }
-
-    pub fn new_with_type(
-        typ: &'static CreatureType<'static>,
-        position: Position,
-    ) -> Self {
-        Creature {
-            id: None,
-            typ,
-            position,
-            hitpoints: typ.max_hitpoints,
-        }
-    }
-
-    /// Damage the given creature by the given amount
-    pub fn damage(&mut self, amount: u16) {
-        if self.hitpoints <= amount {
-            self.hitpoints = 0;
-        } else {
-            self.hitpoints -= amount;
-        }
-    }
-
-    /// Returns true if this creature has died
-    pub fn dead(&self) -> bool {
-        self.hitpoints == 0
-    }
-}
-
-entity!(Creature);
-
-impl Describe for Creature {
-    fn description(&self) -> String {
-        self.typ.description.to_string()
-    }
-}
-
-impl display::Draw for Creature {
-    fn do_draw(&self, out: &mut dyn Write) -> io::Result<()> {
-        write!(out, "{}", self.typ.chr)
-    }
-}
diff --git a/src/entities/entity.rs b/src/entities/entity.rs
deleted file mode 100644
index 01075d298f81..000000000000
--- a/src/entities/entity.rs
+++ /dev/null
@@ -1,125 +0,0 @@
-use crate::display::DrawWithNeighbors;
-use crate::entities::EntityID;
-use crate::types::Neighbors;
-use crate::types::Position;
-use crate::types::{Positioned, PositionedMut};
-use downcast_rs::Downcast;
-use std::fmt::Debug;
-use std::io::{self, Write};
-
-pub trait Identified<ID>: Debug {
-    fn opt_id(&self) -> Option<ID>;
-    fn set_id(&mut self, id: ID);
-
-    fn id(&self) -> ID {
-        self.opt_id()
-            .unwrap_or_else(|| panic!("Entity ({:?}) is not in the game", self))
-    }
-}
-
-impl<'a, A, ID> Identified<ID> for &'a mut A
-where
-    A: Identified<ID>,
-{
-    fn opt_id(&self) -> Option<ID> {
-        (**self).opt_id()
-    }
-    fn set_id(&mut self, id: ID) {
-        (**self).set_id(id);
-    }
-}
-
-impl<ID, A: Identified<ID>> Identified<ID> for Box<A> {
-    fn opt_id(&self) -> Option<ID> {
-        (**self).opt_id()
-    }
-    fn set_id(&mut self, id: ID) {
-        (**self).set_id(id);
-    }
-}
-
-pub trait Describe {
-    fn description(&self) -> String;
-}
-
-ref_impl! {
-    impl<T: Describe> Describe for &T {
-        fn description(&self) -> String {
-            (**self).description()
-        }
-    }
-}
-
-#[macro_export]
-macro_rules! static_description {
-    ($name: ident, $description: expr) => {
-        impl $crate::entities::entity::Describe for $name {
-            fn description(&self) -> String {
-                $description.to_string()
-            }
-        }
-    };
-}
-
-pub trait Entity:
-    Positioned
-    + PositionedMut
-    + Identified<EntityID>
-    + DrawWithNeighbors
-    + Downcast
-    + Describe
-{
-}
-
-impl Identified<EntityID> for Box<dyn Entity> {
-    fn opt_id(&self) -> Option<EntityID> {
-        (**self).opt_id()
-    }
-    fn set_id(&mut self, id: EntityID) {
-        (**self).set_id(id);
-    }
-}
-
-#[macro_export]
-macro_rules! identified {
-    ($name: ident, $typ: path) => {
-        identified!($name, $typ, id);
-    };
-    ($name: ident, $typ: path, $attr: ident) => {
-        impl crate::entities::entity::Identified<$typ> for $name {
-            fn opt_id(&self) -> Option<$typ> {
-                self.$attr
-            }
-
-            fn set_id(&mut self, id: $typ) {
-                self.$attr = Some(id)
-            }
-        }
-    };
-}
-
-impl_downcast!(Entity);
-
-impl DrawWithNeighbors for Box<dyn Entity> {
-    fn do_draw_with_neighbors<'a, 'b>(
-        &'a self,
-        out: &'b mut dyn Write,
-        neighbors: &'a Neighbors<Vec<&'a Box<dyn Entity>>>,
-    ) -> io::Result<()> {
-        (**self).do_draw_with_neighbors(out, neighbors)
-    }
-}
-
-pub type AnEntity = Box<dyn Entity>;
-
-impl Positioned for AnEntity {
-    fn position(&self) -> Position {
-        (**self).position()
-    }
-}
-
-impl PositionedMut for AnEntity {
-    fn set_position(&mut self, pos: Position) {
-        (**self).set_position(pos)
-    }
-}
diff --git a/src/entities/entity_char.rs b/src/entities/entity_char.rs
deleted file mode 100644
index 70f26bfffdbd..000000000000
--- a/src/entities/entity_char.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-use crate::display::color::Color;
-use std::fmt::{self, Display, Formatter};
-use termion::color;
-
-#[derive(Debug, Deserialize, PartialEq, Eq)]
-pub struct EntityChar {
-    #[serde(default)]
-    color: Color,
-
-    #[serde(rename = "char")]
-    chr: char,
-}
-
-impl Display for EntityChar {
-    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "{}{}{}",
-            color::Fg(&self.color),
-            self.chr,
-            color::Fg(color::Reset)
-        )
-    }
-}
diff --git a/src/entities/environment.rs b/src/entities/environment.rs
deleted file mode 100644
index 8f8a56706287..000000000000
--- a/src/entities/environment.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-use crate::display;
-use crate::display::draw_box::{BoxStyle, Stylable};
-use crate::entities::Entity;
-use crate::types::{Neighbors, Position};
-use std::io::{self, Write};
-
-entity! {
-    pub struct Wall {
-        pub style: BoxStyle
-    }
-}
-
-static_description!(Wall, "a wall");
-
-impl Wall {
-    pub fn new(position: Position, style: BoxStyle) -> Self {
-        new_entity!(Wall { position, style })
-    }
-}
-
-impl display::DrawWithNeighbors for Wall {
-    fn do_draw_with_neighbors<'a, 'b>(
-        &'a self,
-        out: &'b mut dyn Write,
-        neighbors: &'a Neighbors<Vec<&'a Box<dyn Entity>>>,
-    ) -> io::Result<()> {
-        let neighbor_styles: Neighbors<Option<BoxStyle>> =
-            neighbors.map(|es| {
-                es.iter()
-                    .filter_map(|e| e.downcast_ref::<Wall>())
-                    .map(|wall| wall.style)
-                    .next()
-            });
-        write!(out, "{}", neighbor_styles.style(self.style))
-    }
-}
diff --git a/src/entities/item.rs b/src/entities/item.rs
deleted file mode 100644
index 5f08780d4fb2..000000000000
--- a/src/entities/item.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-use crate::display;
-use crate::entities::raws::{raw, EntityRaw, ItemType};
-use crate::entities::{Describe, EntityID};
-use crate::types::Position;
-use std::io::{self, Write};
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Item {
-    pub id: Option<EntityID>,
-    pub typ: &'static ItemType<'static>,
-    pub position: Position,
-}
-
-impl Item {
-    pub fn new_from_raw(name: &'static str, position: Position) -> Self {
-        match raw(name) {
-            EntityRaw::Item(typ) => Self::new_with_type(typ, position),
-            _ => panic!("Invalid raw type for {:?}, expected Item", name),
-        }
-    }
-
-    pub fn new_with_type(
-        typ: &'static ItemType<'static>,
-        position: Position,
-    ) -> Self {
-        Item {
-            id: None,
-            typ,
-            position,
-        }
-    }
-
-    pub fn is_edible(&self) -> bool {
-        self.typ.is_edible()
-    }
-}
-
-entity!(Item);
-
-impl Describe for Item {
-    fn description(&self) -> String {
-        self.typ.description.to_string()
-    }
-}
-
-impl display::Draw for Item {
-    fn do_draw(&self, out: &mut dyn Write) -> io::Result<()> {
-        write!(out, "{}", self.typ.chr)
-    }
-}
diff --git a/src/entities/mod.rs b/src/entities/mod.rs
deleted file mode 100644
index a8c39ed8aa78..000000000000
--- a/src/entities/mod.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-#[macro_use]
-pub mod entity;
-#[macro_use]
-pub mod util;
-pub mod character;
-pub mod creature;
-pub mod entity_char;
-pub mod environment;
-pub mod item;
-pub mod raw_types;
-pub mod raws;
-
-pub use character::Character;
-pub use creature::Creature;
-pub use entity::{AnEntity, Describe, Entity, Identified};
-pub use entity_char::EntityChar;
-pub use item::Item;
-pub use raws::raw;
-
-pub type EntityID = u32;
diff --git a/src/entities/raw_types.rs b/src/entities/raw_types.rs
deleted file mode 100644
index 4bc291b69580..000000000000
--- a/src/entities/raw_types.rs
+++ /dev/null
@@ -1,110 +0,0 @@
-use crate::entities::entity_char::EntityChar;
-use crate::messages::Message;
-use crate::types::Speed;
-
-#[derive(Debug, Deserialize)]
-pub struct CreatureType<'a> {
-    /// The name of the creature. Used in raw lookups.
-    pub name: &'a str,
-
-    /// A description of the entity, used by the "look" command
-    pub description: &'a str,
-
-    #[serde(rename = "char")]
-    pub chr: EntityChar,
-    pub max_hitpoints: u16,
-    pub speed: Speed,
-    pub friendly: bool,
-}
-
-#[derive(Debug, Deserialize, PartialEq, Eq)]
-pub struct EdibleItem<'a> {
-    #[serde(borrow)]
-    pub eat_message: Option<Message<'a>>,
-
-    /// The number of hitpoints that eating this item heals
-    pub hitpoints_healed: u16,
-}
-
-#[derive(Debug, Deserialize, PartialEq, Eq)]
-pub struct ItemType<'a> {
-    pub name: &'a str,
-
-    /// A description of the item, used by the "look" command and when walking
-    /// over the item on the ground
-    pub description: &'a str,
-
-    /// A longer description of the item
-    pub long_description: &'a str,
-
-    pub edible_item: Option<EdibleItem<'a>>,
-
-    #[serde(rename = "char")]
-    pub chr: EntityChar,
-}
-
-#[cfg(test)]
-mod item_type_tests {
-    use super::*;
-
-    #[test]
-    fn test_deserialize_item_type() {
-        let result = serde_json::from_str(
-            r#"{
-                "Item": {
-                    "name": "noodles",
-                    "description": "a big bowl o' noodles",
-                    "long_description": "You know exactly what kind of noodles",
-                    "char": { "char": "n" },
-                    "edible_item": {
-                        "eat_message": "You slurp up the noodles",
-                        "hitpoints_healed": 2
-                    }
-                }
-            }"#,
-        )
-        .unwrap();
-        assert_matches!(result, EntityRaw::Item(_));
-        if let EntityRaw::Item(item) = result {
-            assert_eq!(item.name, "noodles");
-        }
-
-        let toml_result = toml::from_str(
-            r#"[Item]
-name = "noodles"
-description = "a big bowl o' noodles"
-long_description = "You know exactly what kind of noodles"
-char = { char = "๐Ÿœ" }
-edible_item = { eat_message = "You slurp up the noodles", hitpoints_healed = 2 }
-"#,
-        )
-        .unwrap();
-
-        assert_matches!(toml_result, EntityRaw::Item(_));
-        if let EntityRaw::Item(item) = toml_result {
-            assert_eq!(item.name, "noodles");
-        }
-    }
-}
-
-impl<'a> ItemType<'a> {
-    pub fn is_edible(&self) -> bool {
-        self.edible_item.is_some()
-    }
-}
-
-#[derive(Debug, Deserialize)]
-pub enum EntityRaw<'a> {
-    Creature(#[serde(borrow)] CreatureType<'a>),
-    Item(#[serde(borrow)] ItemType<'a>),
-}
-
-impl<'a> EntityRaw<'a> {
-    pub fn name(&self) -> &'a str {
-        use EntityRaw::*;
-        match self {
-            Creature(typ) => typ.name,
-            Item(typ) => typ.name,
-        }
-    }
-}
diff --git a/src/entities/raws.rs b/src/entities/raws.rs
deleted file mode 100644
index 061e29a84037..000000000000
--- a/src/entities/raws.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-pub use crate::entities::raw_types::{CreatureType, EntityRaw, ItemType};
-use std::collections::HashMap;
-
-static_cfg! {
-    static ref RAWS: Vec<EntityRaw<'static>> = cfg_dir("src/entities/raws");
-}
-
-lazy_static! {
-    static ref RAWS_BY_NAME: HashMap<&'static str, &'static EntityRaw<'static>> = {
-        let mut hm = HashMap::new();
-        for er in RAWS.iter() {
-            if hm.contains_key(er.name()) {
-                panic!("Duplicate entity: {}", er.name())
-            }
-
-            hm.insert(er.name(), er);
-        }
-        hm
-    };
-}
-
-pub fn raw(name: &'static str) -> &'static EntityRaw<'static> {
-    RAWS_BY_NAME
-        .get(name)
-        .copied()
-        .unwrap_or_else(|| panic!("Raw not found: {}", name))
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn test_raws() {
-        RAWS_BY_NAME.keys();
-        assert_eq!(raw("noodles").name(), "noodles");
-    }
-}
diff --git a/src/entities/raws/gormlak.toml b/src/entities/raws/gormlak.toml
deleted file mode 100644
index be30362d25bd..000000000000
--- a/src/entities/raws/gormlak.toml
+++ /dev/null
@@ -1,10 +0,0 @@
-[Creature]
-name = "gormlak"
-description = """
-A chittering imp-like creature with bright yellow horns. It adores shiny objects
-and gathers in swarms.
-"""
-char = { char = "g", color = "red" }
-max_hitpoints = 5
-speed = 120
-friendly = false
diff --git a/src/entities/raws/noodles.json b/src/entities/raws/noodles.json
deleted file mode 100644
index dfa2609f5ecb..000000000000
--- a/src/entities/raws/noodles.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "Item": {
-    "name": "noodles",
-    "char": {
-      "char": "n",
-      "color": "yellow"
-    },
-    "description": "a big bowl o' noodles",
-    "long_description": "You know exactly what kind of noodles",
-    "edible_item": {
-      "eat_message": "You slurp up the noodles",
-      "hitpoints_healed": 2
-    }
-  }
-}
diff --git a/src/entities/util.rs b/src/entities/util.rs
deleted file mode 100644
index 6c11ffadf994..000000000000
--- a/src/entities/util.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-#[macro_export]
-macro_rules! new_entity {
-    ($name: ident) => {
-        new_entity!($name, {})
-    };
-
-    ($name: ident { position: $position:expr $(, $fields:tt)* }) => {
-        $name {
-            id: None,
-            position: $position,
-            $($fields)*
-        }
-    };
-
-    ($name: ident { $position:expr $(, $fields:tt)* }) => {
-        $name {
-            id: None,
-            position: $position,
-            $($fields)*
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! boring_entity {
-    ($name:ident) => {
-        entity! {
-            pub struct $name {}
-        }
-
-        impl $name {
-            #[allow(dead_code)]
-            pub fn new(position: $crate::types::Position) -> Self {
-                $name { id: None, position }
-            }
-        }
-    };
-
-    ($name:ident, char: $char: expr) => {
-        boring_entity!($name);
-
-        impl $crate::display::Draw for $name {
-            fn do_draw(&self, out: &mut Write) -> io::Result<()> {
-                write!(out, "{}", $char)
-            }
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! entity {
-    ($name: ident) => {
-        positioned!($name);
-        positioned_mut!($name);
-        identified!($name, $crate::entities::EntityID);
-        impl $crate::entities::entity::Entity for $name {}
-    };
-
-    (pub struct $name:ident { $($struct_contents:tt)* } $($rest:tt)*) => {
-        #[derive(Debug, PartialEq, Eq, Clone)]
-        pub struct $name {
-            pub id: Option<$crate::entities::EntityID>,
-            pub position: $crate::types::Position,
-            $($struct_contents)*
-        }
-
-        entity!($name);
-        entity!($($rest)*);
-    };
-
-    () => {};
-}
diff --git a/src/game.rs b/src/game.rs
deleted file mode 100644
index c478e0d2f55b..000000000000
--- a/src/game.rs
+++ /dev/null
@@ -1,617 +0,0 @@
-use crate::description::list_to_sentence;
-use crate::display::{self, Viewport};
-use crate::entities::entity::Describe;
-use crate::entities::entity::Entity;
-use crate::entities::{
-    AnEntity, Character, Creature, EntityID, Identified, Item,
-};
-use crate::messages::message;
-use crate::settings::Settings;
-use crate::types::command::Command;
-use crate::types::entity_map::EntityMap;
-use crate::types::{
-    pos, BoundingBox, Collision, Dimensions, Position, Positioned, Ticks,
-};
-use crate::util::promise::Cancelled;
-use crate::util::promise::{promise, Complete, Promise, Promises};
-use crate::util::template::TemplateParams;
-use rand::rngs::SmallRng;
-use rand::SeedableRng;
-use std::io::{self, StdinLock, StdoutLock, Write};
-use termion::input::Keys;
-use termion::input::TermRead;
-use termion::raw::RawTerminal;
-
-type Stdout<'a> = RawTerminal<StdoutLock<'a>>;
-
-type Rng = SmallRng;
-
-enum PromptResolution {
-    Uncancellable(Complete<String>),
-    Cancellable(Complete<Result<String, Cancelled>>),
-}
-
-/// The mode to use when describing entities on a tile to the user
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-enum EntityDescriptionMode {
-    /// Describe the entities that the user is walking over.
-    ///
-    /// This means:
-    /// - Skip the character themselves
-    /// - Describe nothing if there are no items other than the character
-    Walk,
-
-    /// Describe entities that the user is actively asking about.
-    ///
-    /// This means:
-    /// - Describe the character themselves if they've asked to look at the tile
-    ///   they're standing on
-    /// - Explicitly say there's nothing there if there's nothing there.
-    Look,
-}
-
-impl PromptResolution {
-    fn is_cancellable(&self) -> bool {
-        use PromptResolution::*;
-        match self {
-            Uncancellable(_) => false,
-            Cancellable(_) => true,
-        }
-    }
-
-    fn fulfill(&mut self, val: String) {
-        use PromptResolution::*;
-        match self {
-            Cancellable(complete) => complete.ok(val),
-            Uncancellable(complete) => complete.fulfill(val),
-        }
-    }
-
-    fn cancel(&mut self) {
-        use PromptResolution::*;
-        match self {
-            Cancellable(complete) => complete.cancel(),
-            Uncancellable(_complete) => {}
-        }
-    }
-}
-
-/// The kind of input the game is waiting to receive
-enum InputState {
-    /// The initial input state of the game - we're currently waiting for direct
-    /// commands.
-    Initial,
-
-    /// A free text prompt has been shown to the user, and every character
-    /// besides "escape" is interpreted as a response to that prompt
-    Prompt {
-        complete: PromptResolution,
-        buffer: String,
-    },
-}
-
-impl InputState {
-    fn uncancellable_prompt(complete: Complete<String>) -> Self {
-        InputState::Prompt {
-            complete: PromptResolution::Uncancellable(complete),
-            buffer: String::new(),
-        }
-    }
-
-    fn cancellable_prompt(
-        complete: Complete<Result<String, Cancelled>>,
-    ) -> Self {
-        InputState::Prompt {
-            complete: PromptResolution::Cancellable(complete),
-            buffer: String::new(),
-        }
-    }
-}
-
-impl Default for InputState {
-    fn default() -> Self {
-        InputState::Initial
-    }
-}
-
-/// The full state of a running Game
-pub struct Game<'a> {
-    settings: Settings,
-
-    viewport: Viewport<Stdout<'a>>,
-
-    /// An iterator on keypresses from the user
-    keys: Keys<StdinLock<'a>>,
-
-    /// The kind of input the game is waiting to receive
-    input_state: InputState,
-
-    /// The map of all the entities in the game
-    entities: EntityMap<AnEntity>,
-
-    /// The entity ID of the player character
-    character_entity_id: EntityID,
-
-    /// The messages that have been said to the user, in forward time order
-    messages: Vec<String>,
-
-    /// The index of the currently-displayed message. Used to track the index of
-    /// the currently displayed message when handling PreviousMessage commands
-    message_idx: usize,
-
-    /// A global random number generator for the game
-    rng: Rng,
-
-    /// A list of promises that are waiting on the game and a result
-    promises: Promises<'a, Self>,
-}
-
-impl<'a> Game<'a> {
-    pub fn new(
-        settings: Settings,
-        stdout: RawTerminal<StdoutLock<'a>>,
-        stdin: StdinLock<'a>,
-        w: u16,
-        h: u16,
-    ) -> Game<'a> {
-        let rng = match settings.seed {
-            Some(seed) => SmallRng::seed_from_u64(seed),
-            None => SmallRng::from_entropy(),
-        };
-        let mut entities: EntityMap<AnEntity> = EntityMap::new();
-
-        // TODO make this dynamic
-        {
-            entities.insert(Box::new(Creature::new_from_raw(
-                "gormlak",
-                pos(10, 0),
-            )));
-
-            entities
-                .insert(Box::new(Item::new_from_raw("noodles", pos(0, 10))));
-        }
-
-        Game {
-            settings,
-            rng,
-            message_idx: 0,
-            viewport: Viewport::new(
-                BoundingBox::at_origin(Dimensions { w, h }),
-                BoundingBox::at_origin(Dimensions { w: w - 2, h: h - 2 }),
-                stdout,
-            ),
-            keys: stdin.keys(),
-            input_state: Default::default(),
-            character_entity_id: entities.insert(Box::new(Character::new())),
-            messages: Vec::new(),
-            entities,
-            promises: Promises::new(),
-        }
-    }
-
-    fn downcast_entities_at<A: Entity>(&self, pos: Position) -> Vec<&A> {
-        self.entities
-            .at(pos)
-            .iter()
-            .filter_map(|e| e.downcast_ref())
-            .collect()
-    }
-
-    /// Returns a list of all creature entities at the given position
-    fn creatures_at(&self, pos: Position) -> Vec<&Creature> {
-        self.downcast_entities_at(pos)
-    }
-
-    /// Returns a list of all item entities at the given position
-    fn items_at(&self, pos: Position) -> Vec<&Item> {
-        self.downcast_entities_at(pos)
-    }
-
-    /// Returns a collision, if any, at the given Position in the game
-    fn collision_at(&self, pos: Position) -> Option<Collision> {
-        if !pos.within(self.viewport.inner) {
-            Some(Collision::Stop)
-        } else if self.creatures_at(pos).is_empty() {
-            None
-        } else {
-            Some(Collision::Combat)
-        }
-    }
-
-    fn character(&self) -> &Character {
-        (*self.entities.get(self.character_entity_id).unwrap())
-            .downcast_ref()
-            .unwrap()
-    }
-
-    fn mut_character(&mut self) -> &mut Character {
-        (*self.entities.get_mut(self.character_entity_id).unwrap())
-            .downcast_mut()
-            .unwrap()
-    }
-
-    /// Draw all the game entities to the screen
-    fn draw_entities(&mut self) -> io::Result<()> {
-        for entity in self.entities.entities() {
-            self.viewport.draw(
-                entity,
-                &self.entities.neighbor_entities(entity.position()),
-            )?;
-        }
-        Ok(())
-    }
-
-    /// Draw all the game entities to the screen
-    fn draw_entities_at(&mut self, pos: Position) -> io::Result<()> {
-        for entity in self.entities.at(pos) {
-            self.viewport.draw(
-                entity,
-                &self.entities.neighbor_entities(entity.position()),
-            )?;
-        }
-        Ok(())
-    }
-
-    /// Draw the game entity with the given ID, if any, to the screen
-    fn draw_entity(&mut self, entity_id: EntityID) -> io::Result<bool> {
-        if let Some(entity) = self.entities.get(entity_id) {
-            self.viewport.draw(
-                entity,
-                &self.entities.neighbor_entities(entity.position()),
-            )?;
-            Ok(true)
-        } else {
-            Ok(false)
-        }
-    }
-
-    /// Describe all the entities at a given position to the user.
-    ///
-    /// If `force` is not set to `true`, will not do anything if there are no
-    /// entities
-    fn describe_entities_at(
-        &mut self,
-        pos: Position,
-        mode: EntityDescriptionMode,
-    ) -> io::Result<()> {
-        use EntityDescriptionMode::*;
-        let mut entities = self.entities.at(pos);
-        if mode == Walk {
-            entities.retain(|e| e.id() != self.character_entity_id);
-        }
-
-        if entities.is_empty() {
-            match mode {
-                Walk => return Ok(()),
-                Look => {
-                    return self.say(
-                        "global.describe_no_entities",
-                        &template_params!(),
-                    )
-                }
-            }
-        }
-
-        let descriptions = list_to_sentence(
-            &entities
-                .iter()
-                .map(|e| e.description())
-                .collect::<Vec<String>>(),
-        );
-
-        self.say(
-            "global.describe_entities",
-            &template_params!({ "descriptions" => &descriptions, }),
-        )
-    }
-
-    /// Remove the given entity from the game, drawing over it if it's visible
-    fn remove_entity(&mut self, entity_id: EntityID) -> io::Result<()> {
-        if let Some(entity) = self.entities.remove(entity_id) {
-            self.viewport.clear(entity.position())?;
-        }
-        Ok(())
-    }
-
-    /// Step the game forward the given number of ticks
-    fn tick(&mut self, _ticks: Ticks) {}
-
-    /// Get a message from the global map based on the rng in this game
-    fn message<'params>(
-        &mut self,
-        name: &'static str,
-        params: &TemplateParams<'params>,
-    ) -> String {
-        message(name, &mut self.rng, params)
-    }
-
-    /// Say a message to the user
-    fn say<'params>(
-        &mut self,
-        message_name: &'static str,
-        params: &TemplateParams<'params>,
-    ) -> io::Result<()> {
-        let message = self.message(message_name, params);
-        self.messages.push(message.to_string());
-        self.message_idx = self.messages.len() - 1;
-        self.viewport.write_message(&message)?;
-        Ok(())
-    }
-
-    /// Prompt the user for input, returning a Future for the result of the
-    /// prompt
-    fn prompt(
-        &mut self,
-        name: &'static str,
-        params: &TemplateParams<'_>,
-    ) -> io::Result<Promise<Self, String>> {
-        let (complete, promise) = promise();
-        self.input_state = InputState::uncancellable_prompt(complete);
-        let message = self.message(name, params);
-        self.viewport.write_prompt(&message)?;
-        self.promises.push(Box::new(promise.clone()));
-        Ok(promise)
-    }
-
-    fn prompt_cancellable(
-        &mut self,
-        name: &'static str,
-        params: &TemplateParams<'_>,
-    ) -> io::Result<Promise<Self, Result<String, Cancelled>>> {
-        let (complete, promise) = promise();
-        self.input_state = InputState::cancellable_prompt(complete);
-        let message = self.message(name, params);
-        self.viewport.write_prompt(&message)?;
-        self.promises.push(Box::new(promise.clone()));
-        Ok(promise)
-    }
-
-    fn previous_message(&mut self) -> io::Result<()> {
-        if self.message_idx == 0 {
-            return Ok(());
-        }
-        self.message_idx -= 1;
-        let message = &self.messages[self.message_idx];
-        self.viewport.write_message(message)?;
-        Ok(())
-    }
-
-    fn clear_message(&mut self) -> io::Result<()> {
-        debug!("{:?} {:?}", self.message_idx, self.messages);
-        if self.message_idx == self.messages.len() {
-            return Ok(());
-        }
-        self.viewport.clear_message()?;
-        self.message_idx += 1;
-        Ok(())
-    }
-
-    fn creature(&self, creature_id: EntityID) -> Option<&Creature> {
-        self.entities
-            .get(creature_id)
-            .and_then(|e| e.downcast_ref::<Creature>())
-    }
-
-    fn expect_creature(&self, creature_id: EntityID) -> &Creature {
-        self.creature(creature_id).unwrap_or_else(|| {
-            panic!("Creature ID went away: {:?}", creature_id)
-        })
-    }
-
-    fn mut_creature(&mut self, creature_id: EntityID) -> Option<&mut Creature> {
-        self.entities
-            .get_mut(creature_id)
-            .and_then(|e| e.downcast_mut::<Creature>())
-    }
-
-    fn expect_mut_creature(&mut self, creature_id: EntityID) -> &mut Creature {
-        self.mut_creature(creature_id).unwrap_or_else(|| {
-            panic!("Creature ID went away: {:?}", creature_id)
-        })
-    }
-
-    fn attack(&mut self, creature_id: EntityID) -> io::Result<()> {
-        info!("Attacking creature {:?}", creature_id);
-        let damage = self.character().damage();
-        let creature_name = self.expect_creature(creature_id).typ.name;
-        let tps = template_params!({
-            "creature" => {
-                "name" => creature_name,
-            },
-        });
-        self.say("combat.attack", &tps)?;
-
-        let creature = self.expect_mut_creature(creature_id);
-        creature.damage(damage);
-        if creature.dead() {
-            self.say("combat.killed", &tps)?;
-            info!("Killed creature {:?}", creature_id);
-            self.remove_entity(creature_id)?;
-        }
-        Ok(())
-    }
-
-    fn attack_at(&mut self, pos: Position) -> io::Result<()> {
-        let creatures = self.creatures_at(pos);
-        match creatures.len() {
-            0 => Ok(()),
-            1 => {
-                let creature = creatures.get(0).unwrap();
-                let creature_id = creature.id();
-                self.attack(creature_id)
-            }
-            _ => {
-                // TODO prompt with a menu of creatures to combat
-                unimplemented!()
-            }
-        }
-    }
-
-    fn pick_up(&mut self) -> io::Result<()> {
-        let pos = self.character().position;
-        let items = self.items_at(pos);
-        match items.len() {
-            0 => Ok(()),
-            1 => {
-                let item_id = items.get(0).unwrap().id();
-                let item: Box<Item> =
-                    self.entities.remove(item_id).unwrap().downcast().unwrap();
-                let desc = item.description();
-                self.mut_character().inventory.push(item);
-                self.say(
-                    "global.pick_up",
-                    &template_params!({
-                        "item" => { "name" => &desc, },
-                    }),
-                )
-            }
-            _ => {
-                // TODO prompt with a menu of items to pick up
-                unimplemented!()
-            }
-        }
-    }
-
-    fn flush_promises(&mut self) {
-        unsafe {
-            let game = self as *mut Self;
-            (*game).promises.give_all(&mut *game);
-        }
-    }
-
-    /// Run the game
-    pub fn run(mut self) -> io::Result<()> {
-        info!("Running game");
-        self.viewport.init()?;
-        self.draw_entities()?;
-        self.flush().unwrap();
-
-        self.prompt("character.name_prompt", &template_params!())?
-            .on_fulfill(|game, char_name| {
-                game.say(
-                    "global.welcome",
-                    &template_params!({
-                        "character" => {
-                            "name" => char_name,
-                        },
-                    }),
-                )
-                .unwrap();
-                game.flush().unwrap();
-                game.mut_character().set_name(char_name.to_string());
-            });
-
-        loop {
-            let mut old_position = None;
-            let next_key = self.keys.next().unwrap().unwrap();
-            match &mut self.input_state {
-                InputState::Initial => {
-                    use Command::*;
-                    match Command::from_key(next_key) {
-                        Some(Quit) => {
-                            info!("Quitting game due to user request");
-                            break;
-                        }
-
-                        Some(Move(direction)) => {
-                            use Collision::*;
-                            let new_pos = self.character().position + direction;
-                            match self.collision_at(new_pos) {
-                                None => {
-                                    old_position =
-                                        Some(self.character().position);
-                                    self.entities.update_position(
-                                        self.character_entity_id,
-                                        new_pos,
-                                    );
-                                }
-                                Some(Combat) => {
-                                    self.attack_at(new_pos)?;
-                                }
-                                Some(Stop) => (),
-                            }
-                        }
-
-                        Some(PreviousMessage) => self.previous_message()?,
-
-                        Some(PickUp) => self.pick_up()?,
-
-                        None => (),
-                    }
-
-                    if let Some(old_pos) = old_position {
-                        let character = self.character();
-                        let char_pos = character.position;
-                        self.viewport.game_cursor_position = char_pos;
-                        self.viewport.clear(old_pos)?;
-                        self.draw_entities_at(old_pos)?;
-                        self.draw_entity(self.character_entity_id)?;
-                        self.clear_message()?;
-                        self.describe_entities_at(
-                            char_pos,
-                            EntityDescriptionMode::Walk,
-                        )?;
-                        self.tick(
-                            self.character().speed().tiles_to_ticks(
-                                (old_pos - char_pos).as_tiles(),
-                            ),
-                        );
-                    }
-                }
-
-                InputState::Prompt { complete, buffer } => {
-                    use termion::event::Key::*;
-                    match next_key {
-                        Char('\n') => {
-                            info!("Prompt complete: \"{}\"", buffer);
-                            self.viewport.clear_prompt()?;
-                            complete.fulfill(buffer.clone());
-                            self.input_state = InputState::Initial;
-                        }
-                        Char(chr) => {
-                            buffer.push(chr);
-                            self.viewport.push_prompt_chr(chr)?;
-                        }
-                        Esc => complete.cancel(),
-                        Backspace => {
-                            buffer.pop();
-                            self.viewport.pop_prompt_chr()?;
-                        }
-                        _ => {}
-                    }
-                }
-            }
-
-            self.flush()?;
-            self.flush_promises();
-            debug!("{:?}", self.character());
-        }
-        Ok(())
-    }
-}
-
-impl<'a> Drop for Game<'a> {
-    fn drop(&mut self) {
-        display::clear(self).unwrap_or(());
-    }
-}
-
-impl<'a> Write for Game<'a> {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        self.viewport.write(buf)
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        self.viewport.flush()
-    }
-
-    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
-        self.viewport.write_all(buf)
-    }
-}
-
-impl<'a> Positioned for Game<'a> {
-    fn position(&self) -> Position {
-        Position { x: 0, y: 0 }
-    }
-}
diff --git a/src/level_gen/cave_automata.rs b/src/level_gen/cave_automata.rs
deleted file mode 100644
index e5e2807ab251..000000000000
--- a/src/level_gen/cave_automata.rs
+++ /dev/null
@@ -1,120 +0,0 @@
-use crate::level_gen::util::fill_outer_edges;
-use crate::level_gen::util::rand_initialize;
-use crate::types::Dimensions;
-use rand::Rng;
-
-pub struct Params {
-    chance_to_start_alive: f64,
-    birth_limit: i32,
-    death_limit: i32,
-    steps: usize,
-}
-
-macro_rules! parse_optional {
-    ($out: ident . $attr: ident, $matches: expr, $arg: expr) => {
-        if let Some(val_s) = $matches.value_of($arg) {
-            $out.$attr = val_s.parse().unwrap();
-        }
-    };
-}
-
-macro_rules! parse_optional_matches {
-    ($matches: expr) => {};
-    ($matches: expr , { $ret: ident . $attr: ident = $arg: expr }) => {
-        parse_optional!($ret.$attr, $matches, $arg);
-    };
-    ($matches: expr, { $($ret: ident . $attr: ident = $arg: expr ,)* }) => {
-        $(parse_optional!($ret.$attr, $matches, $arg);)*
-    };
-}
-
-impl Params {
-    pub fn from_matches<'a>(matches: &clap::ArgMatches<'a>) -> Self {
-        let mut ret: Self = Default::default();
-        parse_optional_matches!(matches, {
-            ret.chance_to_start_alive = "start-alive-chance",
-            ret.birth_limit = "birth-limit",
-            ret.death_limit = "death-limit",
-            ret.steps = "steps",
-        });
-        ret
-    }
-}
-
-impl Default for Params {
-    fn default() -> Self {
-        Params {
-            chance_to_start_alive: 0.45,
-            birth_limit: 4,
-            death_limit: 3,
-            steps: 2,
-        }
-    }
-}
-
-pub fn generate<R: Rng + ?Sized>(
-    dimensions: Dimensions,
-    params: &Params,
-    rand: &mut R,
-) -> Vec<Vec<bool>> {
-    let mut cells =
-        rand_initialize(dimensions, rand, params.chance_to_start_alive);
-    for _ in 0..params.steps {
-        step_automata(&mut cells, dimensions, params);
-    }
-
-    fill_outer_edges(&mut cells);
-
-    cells
-}
-
-fn step_automata(
-    cells: &mut Vec<Vec<bool>>,
-    dimensions: Dimensions,
-    params: &Params,
-) {
-    let orig_cells = (*cells).clone();
-    for x in 0..(dimensions.h as usize) {
-        for y in 0..(dimensions.w as usize) {
-            let nbs = num_alive_neighbors(&orig_cells, x as i32, y as i32);
-            if orig_cells[x][y] {
-                if nbs < params.death_limit {
-                    cells[x][y] = false;
-                } else {
-                    cells[x][y] = true;
-                }
-            } else if nbs > params.birth_limit {
-                cells[x][y] = true;
-            } else {
-                cells[x][y] = false;
-            }
-        }
-    }
-}
-
-const COUNT_EDGES_AS_NEIGHBORS: bool = true;
-
-fn num_alive_neighbors(cells: &[Vec<bool>], x: i32, y: i32) -> i32 {
-    let mut count = 0;
-    for i in -1..2 {
-        for j in -1..2 {
-            if i == 0 && j == 0 {
-                continue;
-            }
-
-            let neighbor_x = x + i;
-            let neighbor_y = y + j;
-
-            if (COUNT_EDGES_AS_NEIGHBORS
-                && (neighbor_x < 0
-                    || neighbor_y < 0
-                    || neighbor_x >= (cells.len() as i32)
-                    || neighbor_y >= (cells[0].len()) as i32))
-                || cells[neighbor_x as usize][neighbor_y as usize]
-            {
-                count += 1;
-            }
-        }
-    }
-    count
-}
diff --git a/src/level_gen/mod.rs b/src/level_gen/mod.rs
deleted file mode 100644
index d796a103b11e..000000000000
--- a/src/level_gen/mod.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-use crate::display::draw_box::BoxStyle;
-use crate::display::utils::clone_times;
-use crate::display::DrawWithNeighbors;
-use crate::entities::entity::Entity;
-use crate::entities::environment::Wall;
-use crate::types::entity_map::EntityMap;
-use crate::types::pos;
-use itertools::Itertools;
-use std::io;
-
-pub mod cave_automata;
-pub mod util;
-
-pub fn level_to_entities(level: Vec<Vec<bool>>) -> EntityMap<Box<dyn Entity>> {
-    let mut res: EntityMap<Box<dyn Entity>> = EntityMap::new();
-
-    let xmax = level.len() as i16;
-    let ymax = if xmax == 0 {
-        0i16
-    } else {
-        level[0].len() as i16
-    };
-
-    let get = |mut x: i16, mut y: i16| {
-        if x < 0 {
-            x = 0;
-        }
-        if y < 0 {
-            y = 0;
-        }
-        if x >= xmax - 1 {
-            x = xmax - 1;
-        }
-        if y >= ymax - 1 {
-            y = ymax - 1;
-        }
-        level[x as usize][y as usize]
-    };
-
-    for x in 0..xmax {
-        for y in 0..ymax {
-            if get(x, y) {
-                // don't output walls that are surrounded on all 8 sides by
-                // walls
-                if (x == 0 || get(x - 1, y))
-                    && (y == 0 || get(x, y - 1))
-                    && (x == xmax - 1 || get(x + 1, y))
-                    && (y == ymax - 1 || get(x, y + 1))
-                    && ((x == 0 && y == 0) || get(x - 1, y - 1))
-                    && ((x == 0 && y == ymax - 1) || get(x - 1, y + 1))
-                    && ((x == xmax - 1 && y == 0) || get(x + 1, y - 1))
-                    && ((x == xmax - 1 && y == ymax - 1) || get(x + 1, y + 1))
-                {
-                    continue;
-                }
-                res.insert(Box::new(Wall::new(
-                    pos(y as i16, x as i16),
-                    BoxStyle::Thin,
-                )));
-            }
-        }
-    }
-
-    res
-}
-
-pub fn draw_level<W: io::Write>(
-    level: Vec<Vec<bool>>,
-    out: &mut W,
-) -> io::Result<()> {
-    if level.is_empty() {
-        return Ok(());
-    }
-
-    let mut lines = clone_times::<Vec<char>, Vec<Vec<char>>>(
-        clone_times(' ', level[0].len() as u16),
-        level.len() as u16,
-    );
-
-    let em = level_to_entities(level);
-
-    for entity in em.entities() {
-        let mut buf = Vec::new();
-        entity.do_draw_with_neighbors(
-            &mut buf,
-            &em.neighbor_entities(entity.position()),
-        )?;
-        let buf_s = std::str::from_utf8(&buf).unwrap();
-        if let Some(chr) = buf_s.chars().next() {
-            lines[entity.position().y as usize][entity.position().x as usize] =
-                chr;
-        }
-    }
-
-    let res = lines
-        .iter()
-        .map(|line| line.iter().collect::<String>())
-        .join("\n");
-
-    write!(out, "{}", res)
-}
diff --git a/src/level_gen/util.rs b/src/level_gen/util.rs
deleted file mode 100644
index 4f56fe6c9557..000000000000
--- a/src/level_gen/util.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-use crate::types::Dimensions;
-use rand::{distributions, Rng};
-
-pub fn falses(dims: Dimensions) -> Vec<Vec<bool>> {
-    let mut ret = Vec::with_capacity(dims.h as usize);
-    for _ in 0..dims.h {
-        let mut row = Vec::with_capacity(dims.w as usize);
-        for _ in 0..dims.w {
-            row.push(false);
-        }
-        ret.push(row);
-    }
-    ret
-}
-
-/// Randomly initialize a 2-dimensional boolean vector of the given
-/// `Dimensions`, using the given random number generator and alive chance
-pub fn rand_initialize<R: Rng + ?Sized>(
-    dims: Dimensions,
-    rng: &mut R,
-    alive_chance: f64,
-) -> Vec<Vec<bool>> {
-    let distrib = distributions::Bernoulli::new(alive_chance).unwrap();
-    let mut ret = Vec::with_capacity(dims.h as usize);
-    for _ in 0..dims.h {
-        let mut row = Vec::with_capacity(dims.w as usize);
-        for _ in 0..dims.w {
-            row.push(rng.sample(distrib));
-        }
-        ret.push(row);
-    }
-    ret
-}
-
-/// Fill the outer edges of a generated level with walls
-pub fn fill_outer_edges(level: &mut Vec<Vec<bool>>) {
-    let xmax = level.len();
-    if xmax == 0 {
-        return;
-    }
-    let ymax = level[0].len();
-
-    for row in level.iter_mut() {
-        row[0] = true;
-        row[ymax - 1] = true;
-    }
-
-    for y in 0..level[0].len() {
-        level[0][y] = true;
-        level[xmax - 1][y] = true;
-    }
-}
diff --git a/src/main.rs b/src/main.rs
deleted file mode 100644
index 8004a5739ef5..000000000000
--- a/src/main.rs
+++ /dev/null
@@ -1,130 +0,0 @@
-#[macro_use]
-extern crate log;
-#[macro_use]
-extern crate serde_derive;
-#[macro_use]
-extern crate clap;
-#[macro_use]
-extern crate prettytable;
-#[macro_use]
-extern crate lazy_static;
-#[cfg(test)]
-#[macro_use]
-extern crate maplit;
-#[macro_use]
-extern crate downcast_rs;
-#[macro_use]
-extern crate include_dir;
-#[macro_use]
-extern crate nom;
-#[cfg(test)]
-#[macro_use]
-extern crate matches;
-
-#[macro_use]
-mod util;
-#[macro_use]
-mod types;
-#[macro_use]
-mod entities;
-mod description;
-mod display;
-mod game;
-mod level_gen;
-mod messages;
-mod settings;
-
-use crate::types::Dimensions;
-use clap::App;
-use game::Game;
-use prettytable::format::consts::FORMAT_BOX_CHARS;
-use rand::rngs::SmallRng;
-use rand::SeedableRng;
-use settings::Settings;
-
-use backtrace::Backtrace;
-use std::io::{self, StdinLock, StdoutLock};
-use std::panic;
-
-use termion;
-use termion::raw::IntoRawMode;
-use termion::raw::RawTerminal;
-
-fn init(
-    settings: Settings,
-    stdout: RawTerminal<StdoutLock<'_>>,
-    stdin: StdinLock<'_>,
-    w: u16,
-    h: u16,
-) -> io::Result<()> {
-    panic::set_hook(if settings.logging.print_backtrace {
-        Box::new(|info| (error!("{}\n{:#?}", info, Backtrace::new())))
-    } else {
-        Box::new(|info| (error!("{}\n{:#?}", info, Backtrace::new())))
-    });
-
-    let game = Game::new(settings, stdout, stdin, w, h);
-    game.run()
-}
-
-fn generate_level<'a, W: io::Write>(
-    stdout: &mut W,
-    params: &clap::ArgMatches<'a>,
-) -> io::Result<()> {
-    let mut rand = SmallRng::from_entropy();
-
-    let mut dimensions: Dimensions = Default::default();
-    if let Some(h_s) = params.value_of("height") {
-        dimensions.h = h_s.parse().unwrap();
-    }
-    if let Some(w_s) = params.value_of("width") {
-        dimensions.w = w_s.parse().unwrap();
-    }
-
-    let level = match params.value_of("generator") {
-        None => panic!("Must supply a generator with --generator"),
-        Some("cave_automata") => level_gen::cave_automata::generate(
-            dimensions,
-            &level_gen::cave_automata::Params::from_matches(params),
-            &mut rand,
-        ),
-        Some(gen) => panic!("Unrecognized generator: {}", gen),
-    };
-    level_gen::draw_level(level, stdout)
-}
-
-fn main() -> io::Result<()> {
-    let yaml = load_yaml!("cli.yml");
-    let matches = App::from_yaml(yaml).get_matches();
-    let settings = Settings::load().unwrap();
-    settings.logging.init_log();
-    let stdout = io::stdout();
-    let mut stdout = stdout.lock();
-
-    let stdin = io::stdin();
-    let stdin = stdin.lock();
-
-    let termsize = termion::terminal_size().ok();
-    let (termwidth, termheight) = termsize.unwrap_or((70, 40));
-
-    match matches.subcommand() {
-        ("info", _) => {
-            let mut table = table!(
-                [br->"termwidth", termwidth],
-                [br->"termheight", termheight],
-                [br->"logfile", settings.logging.file],
-                [br->"loglevel", settings.logging.level]
-            );
-            table.set_format(*FORMAT_BOX_CHARS);
-            table.printstd();
-            Ok(())
-        }
-        ("generate-level", params) => {
-            generate_level(&mut stdout, params.unwrap())
-        }
-        _ => {
-            let stdout = stdout.into_raw_mode().unwrap();
-            init(settings, stdout, stdin, termwidth, termheight)
-        }
-    }
-}
diff --git a/src/messages.rs b/src/messages.rs
deleted file mode 100644
index b081389efc9d..000000000000
--- a/src/messages.rs
+++ /dev/null
@@ -1,166 +0,0 @@
-use crate::util::template::Template;
-use crate::util::template::TemplateParams;
-use rand::seq::SliceRandom;
-use rand::Rng;
-use std::collections::HashMap;
-
-#[derive(Deserialize, Debug, PartialEq, Eq)]
-#[serde(untagged)]
-pub enum Message<'a> {
-    #[serde(borrow)]
-    Single(Template<'a>),
-    Choice(Vec<Template<'a>>),
-}
-
-impl<'a> Message<'a> {
-    fn resolve<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<&Template<'a>> {
-        use Message::*;
-        match self {
-            Single(msg) => Some(msg),
-            Choice(msgs) => msgs.choose(rng),
-        }
-    }
-}
-
-#[derive(Deserialize, Debug, PartialEq, Eq)]
-#[serde(untagged)]
-enum NestedMap<'a> {
-    #[serde(borrow)]
-    Direct(Message<'a>),
-    #[serde(borrow)]
-    Nested(HashMap<&'a str, NestedMap<'a>>),
-}
-
-impl<'a> NestedMap<'a> {
-    fn lookup(&'a self, path: &str) -> Option<&'a Message<'a>> {
-        use NestedMap::*;
-        let leaf =
-            path.split('.')
-                .fold(Some(self), |current, key| match current {
-                    Some(Nested(m)) => m.get(key),
-                    _ => None,
-                });
-        match leaf {
-            Some(Direct(msg)) => Some(msg),
-            _ => None,
-        }
-    }
-}
-
-#[cfg(test)]
-mod nested_map_tests {
-    use super::*;
-
-    #[test]
-    fn test_deserialize_nested_map() {
-        let src = r#"
-[global]
-hello = "Hello World!"
-
-[foo.bar]
-single = "Single"
-choice = ["Say this", "Or this"]
-"#;
-        let result = toml::from_str(src);
-        assert_eq!(
-            result,
-            Ok(NestedMap::Nested(hashmap! {
-                "global" => NestedMap::Nested(hashmap!{
-                    "hello" => NestedMap::Direct(Message::Single(Template::parse("Hello World!").unwrap())),
-                }),
-                "foo" => NestedMap::Nested(hashmap!{
-                    "bar" => NestedMap::Nested(hashmap!{
-                        "single" => NestedMap::Direct(Message::Single(
-                            Template::parse("Single").unwrap()
-                        )),
-                        "choice" => NestedMap::Direct(Message::Choice(
-                            vec![
-                                Template::parse("Say this").unwrap(),
-                                Template::parse("Or this").unwrap()
-                            ]
-                        ))
-                    })
-                })
-            }))
-        )
-    }
-
-    #[test]
-    fn test_lookup() {
-        let map: NestedMap<'static> = toml::from_str(
-            r#"
-[global]
-hello = "Hello World!"
-
-[foo.bar]
-single = "Single"
-choice = ["Say this", "Or this"]
-"#,
-        )
-        .unwrap();
-
-        assert_eq!(
-            map.lookup("global.hello"),
-            Some(&Message::Single(Template::parse("Hello World!").unwrap()))
-        );
-        assert_eq!(
-            map.lookup("foo.bar.single"),
-            Some(&Message::Single(Template::parse("Single").unwrap()))
-        );
-        assert_eq!(
-            map.lookup("foo.bar.choice"),
-            Some(&Message::Choice(vec![
-                Template::parse("Say this").unwrap(),
-                Template::parse("Or this").unwrap()
-            ]))
-        );
-    }
-}
-
-// static MESSAGES_RAW: &'static str = include_str!("messages.toml");
-
-static_cfg! {
-    static ref MESSAGES: NestedMap<'static> = toml_file("messages.toml");
-}
-
-pub fn get<R: Rng + ?Sized>(
-    name: &'static str,
-    rng: &mut R,
-) -> Option<&'static Template<'static>> {
-    MESSAGES.lookup(name).and_then(|msg| msg.resolve(rng))
-}
-
-/// Look up and format a game message based on the given (dot-separated) name,
-/// with the given random generator used to select from choice-based messages
-pub fn message<'a, R: Rng + ?Sized>(
-    name: &'static str,
-    rng: &mut R,
-    params: &TemplateParams<'a>,
-) -> String {
-    match get(name, rng) {
-        Some(msg) => msg.format(params).unwrap_or_else(|e| {
-            error!("Error formatting template: {}", e);
-            "Template Error".to_string()
-        }),
-        None => {
-            error!("Message not found: {}", name);
-            "Template Not Found".to_string()
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use rand::rngs::SmallRng;
-    use rand::SeedableRng;
-
-    #[test]
-    fn test_static_messages() {
-        message(
-            "global.welcome",
-            &mut SmallRng::from_entropy(),
-            &template_params!(),
-        );
-    }
-}
diff --git a/src/messages.toml b/src/messages.toml
deleted file mode 100644
index a9a6b2e009a6..000000000000
--- a/src/messages.toml
+++ /dev/null
@@ -1,27 +0,0 @@
-[global]
-welcome = "Welcome to Xanthous, {{character.name}}! It's dangerous out there, why not stay inside?"
-describe_entities = "You see here {{descriptions}}"
-describe_no_entities = "You see nothing here."
-pick_up = "You pick up the {{item.name}}."
-
-[combat]
-attack = "You attack the {{creature.name}}."
-killed = [
-    "You've killed the {{creature.name}}.",
-    "The {{creature.name}} dies.",
-    "The {{creature.name}} kicks it.",
-    "The {{creature.name}} beefs it."
-    ]
-
-[character]
-name_prompt = [
-    "Hey there friend. What's your name?",
-    "Hey there friend. What should we call you?",
-    "Howdy. What's your name?",
-    "Name please!",
-    "What's your name?",
-    "Hey, what's your name?",
-]
-
-[defaults.item]
-eat = "You eat the {{item.name}}. {{action.result}}"
diff --git a/src/settings.rs b/src/settings.rs
deleted file mode 100644
index 1f205814d1dd..000000000000
--- a/src/settings.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-use config::{Config, ConfigError};
-use log::LevelFilter;
-use log4rs::append::file::FileAppender;
-use log4rs::config::{Appender, Root};
-use log4rs::encode::pattern::PatternEncoder;
-
-#[derive(Debug, Deserialize, Clone)]
-pub struct Logging {
-    #[serde(default = "Logging::default_level")]
-    pub level: LevelFilter,
-
-    #[serde(default = "Logging::default_file")]
-    pub file: String,
-
-    #[serde(default = "Logging::default_print_backtrace")]
-    pub print_backtrace: bool,
-}
-
-impl Default for Logging {
-    fn default() -> Self {
-        Logging {
-            level: LevelFilter::Off,
-            file: "debug.log".to_string(),
-            print_backtrace: true,
-        }
-    }
-}
-
-impl Logging {
-    pub fn init_log(&self) {
-        let logfile = FileAppender::builder()
-            .encoder(Box::new(PatternEncoder::new("{d} {l} - {m}\n")))
-            .build(self.file.clone())
-            .unwrap();
-
-        let config = log4rs::config::Config::builder()
-            .appender(Appender::builder().build("logfile", Box::new(logfile)))
-            .build(Root::builder().appender("logfile").build(self.level))
-            .unwrap();
-
-        log4rs::init_config(config).unwrap();
-    }
-
-    fn default_level() -> LevelFilter {
-        Logging::default().level
-    }
-
-    fn default_file() -> String {
-        Logging::default().file
-    }
-
-    fn default_print_backtrace() -> bool {
-        Logging::default().print_backtrace
-    }
-}
-
-#[derive(Debug, Deserialize, Clone)]
-pub struct Settings {
-    pub seed: Option<u64>,
-    pub logging: Logging,
-}
-
-impl Settings {
-    pub fn load() -> Result<Self, ConfigError> {
-        let mut s = Config::new();
-        s.merge(config::File::with_name("Config").required(false))?;
-        s.merge(config::Environment::with_prefix("XAN"))?;
-        s.try_into()
-    }
-}
diff --git a/src/types/collision.rs b/src/types/collision.rs
deleted file mode 100644
index 59c60e69ee50..000000000000
--- a/src/types/collision.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-/// Describes a kind of game collision
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum Collision {
-    /// Stop moving - you can't move there!
-    Stop,
-
-    /// Moving into an entity at the given position indicates combat
-    Combat,
-}
diff --git a/src/types/command.rs b/src/types/command.rs
deleted file mode 100644
index 17ca4d280fd8..000000000000
--- a/src/types/command.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-use super::Direction;
-use super::Direction::*;
-use termion::event::Key;
-use termion::event::Key::{Char, Ctrl};
-
-pub enum Command {
-    /// Quit the game
-    Quit,
-
-    /// Move the character in a direction
-    Move(Direction),
-
-    /// Pick up any item(s) at the current position
-    PickUp,
-
-    /// Display the previous message
-    PreviousMessage,
-}
-
-impl Command {
-    pub fn from_key(k: Key) -> Option<Command> {
-        use Command::*;
-        match k {
-            Char('q') => Some(Quit),
-
-            Char('h') | Char('a') | Key::Left => Some(Move(Left)),
-            Char('k') | Char('w') | Key::Up => Some(Move(Up)),
-            Char('j') | Char('s') | Key::Down => Some(Move(Down)),
-            Char('l') | Char('d') | Key::Right => Some(Move(Right)),
-            Char('y') => Some(Move(UpLeft)),
-            Char('u') => Some(Move(UpRight)),
-            Char('b') => Some(Move(DownLeft)),
-            Char('n') => Some(Move(DownRight)),
-
-            Ctrl('p') => Some(PreviousMessage),
-            Char(',') => Some(PickUp),
-
-            _ => None,
-        }
-    }
-}
diff --git a/src/types/direction.rs b/src/types/direction.rs
deleted file mode 100644
index 9b5c0991da8d..000000000000
--- a/src/types/direction.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-use proptest_derive::Arbitrary;
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary)]
-pub enum Direction {
-    Left,
-    Up,
-    Down,
-    Right,
-    UpLeft,
-    UpRight,
-    DownRight,
-    DownLeft,
-}
diff --git a/src/types/entity_map.rs b/src/types/entity_map.rs
deleted file mode 100644
index 202d8b593e15..000000000000
--- a/src/types/entity_map.rs
+++ /dev/null
@@ -1,430 +0,0 @@
-use crate::entities::entity::Identified;
-use crate::entities::EntityID;
-use crate::types::Neighbors;
-use crate::types::Position;
-use crate::types::Positioned;
-use crate::types::PositionedMut;
-use alga::general::{
-    AbstractMagma, AbstractMonoid, AbstractSemigroup, Additive, Identity,
-};
-use std::collections::{hash_map, BTreeMap, HashMap};
-use std::iter::FromIterator;
-
-#[derive(Debug, Clone, Default)]
-pub struct EntityMap<A> {
-    by_position: BTreeMap<Position, Vec<EntityID>>,
-    by_id: HashMap<EntityID, A>,
-    last_id: EntityID,
-}
-
-impl<A: PartialEq> PartialEq for EntityMap<A> {
-    fn eq(&self, other: &Self) -> bool {
-        self.by_position == other.by_position && self.by_id == other.by_id
-    }
-}
-impl<A: Eq> Eq for EntityMap<A> {}
-
-const BY_POS_INVARIANT: &str =
-    "Invariant: All references in EntityMap.by_position should point to existent references in by_id";
-
-impl<A> EntityMap<A> {
-    pub fn new() -> EntityMap<A> {
-        EntityMap {
-            by_position: BTreeMap::new(),
-            by_id: HashMap::new(),
-            last_id: 0,
-        }
-    }
-
-    pub fn len(&self) -> usize {
-        self.by_id.len()
-    }
-
-    /// Returns a list of all entities at the given position
-    pub fn at<'a>(&'a self, pos: Position) -> Vec<&'a A> {
-        self.by_position
-            .get(&pos)
-            .iter()
-            .flat_map(|eids| {
-                eids.iter()
-                    .map(|eid| self.by_id.get(eid).expect(BY_POS_INVARIANT))
-            })
-            .collect()
-    }
-
-    /// Remove all entities at the given position
-    pub fn remove_all_at(&mut self, pos: Position) {
-        if let Some(eids) = self.by_position.remove(&pos) {
-            for eid in eids {
-                self.by_id.remove(&eid).expect(BY_POS_INVARIANT);
-            }
-        }
-    }
-
-    pub fn get(&self, id: EntityID) -> Option<&A> {
-        self.by_id.get(&id)
-    }
-
-    pub fn get_mut(&mut self, id: EntityID) -> Option<&mut A> {
-        self.by_id.get_mut(&id)
-    }
-
-    pub fn entities(&self) -> impl Iterator<Item = &A> {
-        self.by_id.values()
-    }
-
-    pub fn entities_mut(&mut self) -> impl Iterator<Item = &mut A> {
-        self.by_id.values_mut()
-    }
-
-    pub fn ids(&self) -> hash_map::Keys<'_, EntityID, A> {
-        self.by_id.keys()
-    }
-
-    pub fn drain(&mut self) -> Drain<'_, A> {
-        let ids = self.ids().copied().collect::<Vec<_>>();
-        Drain {
-            map: self,
-            ids_iter: Box::new(ids.into_iter()),
-        }
-    }
-
-    fn next_id(&mut self) -> EntityID {
-        self.last_id += 1;
-        self.last_id
-    }
-}
-
-impl<A: Positioned + Identified<EntityID>> EntityMap<A> {
-    pub fn insert(&mut self, mut entity: A) -> EntityID {
-        let pos = entity.position();
-        let entity_id = self.next_id();
-        entity.set_id(entity_id);
-        self.by_id.entry(entity_id).or_insert(entity);
-        self.by_position
-            .entry(pos)
-            .or_insert_with(Vec::new)
-            .push(entity_id);
-        entity_id
-    }
-
-    /// Remove the entity with the given ID
-    pub fn remove(&mut self, id: EntityID) -> Option<A> {
-        self.by_id.remove(&id).map(|e| {
-            let mut empty = false;
-            let position = e.position();
-
-            if let Some(es) = self.by_position.get_mut(&position) {
-                es.retain(|e| *e != id);
-                if es.is_empty() {
-                    empty = true;
-                }
-            }
-
-            if empty {
-                self.by_position.remove(&position);
-            }
-            e
-        })
-    }
-
-    /// Moves all elements from `other` into `Self`, leathing `other` empty.
-    pub fn append(&mut self, other: &mut Self) {
-        // TODO there's probably some perf opportunities here by calling
-        // reserve() on stuff
-        for (_, entity) in other.drain() {
-            self.insert(entity);
-        }
-    }
-
-    /// Gets all 8 neighbors of the given position.
-    pub fn neighbors<'a>(
-        &'a self,
-        position: Position,
-    ) -> Neighbors<Vec<(EntityID, &'a A)>> {
-        Neighbors::of_position(position)
-            .map(|pos| self.at(*pos))
-            .mapmap(&|e| (e.id(), *e))
-    }
-
-    pub fn neighbor_entities<'a>(
-        &'a self,
-        position: Position,
-    ) -> Neighbors<Vec<&'a A>> {
-        self.neighbors(position).mapmap(&|(_eid, ent)| *ent)
-    }
-
-    pub fn check_invariants(&self) {
-        for (id, ent) in &self.by_id {
-            assert_eq!(*id, ent.id());
-        }
-
-        for (pos, ents) in &self.by_position {
-            for eid in ents {
-                let ent = self.by_id.get(eid).unwrap();
-                assert_eq!(*pos, ent.position())
-            }
-        }
-    }
-}
-
-impl<'a, A: Positioned + Identified<EntityID>> IntoIterator
-    for &'a EntityMap<A>
-{
-    type Item = (&'a EntityID, &'a A);
-    type IntoIter = std::collections::hash_map::Iter<'a, EntityID, A>;
-    fn into_iter(self) -> Self::IntoIter {
-        (&self.by_id).iter()
-    }
-}
-
-impl<A: Positioned + Identified<EntityID>> IntoIterator for EntityMap<A> {
-    type Item = (EntityID, A);
-    type IntoIter = std::collections::hash_map::IntoIter<EntityID, A>;
-    fn into_iter(self) -> Self::IntoIter {
-        self.by_id.into_iter()
-    }
-}
-
-impl<A: Positioned + Identified<EntityID>> FromIterator<A> for EntityMap<A> {
-    fn from_iter<I: IntoIterator<Item = A>>(iter: I) -> Self {
-        let mut em = EntityMap::new();
-        for ent in iter {
-            em.insert(ent);
-        }
-        em
-    }
-}
-
-impl<A: Positioned + Identified<EntityID> + Eq + Clone> AbstractMagma<Additive>
-    for EntityMap<A>
-{
-    fn operate(&self, right: &Self) -> Self {
-        let mut by_position = self.by_position.clone();
-        by_position.append(&mut right.by_position.clone());
-
-        let mut by_id = self.by_id.clone();
-        for (k, v) in right.by_id.clone() {
-            by_id.insert(k, v);
-        }
-
-        EntityMap {
-            by_position,
-            by_id,
-            last_id: self.last_id.max(right.last_id),
-        }
-    }
-}
-
-impl<A: Positioned + Identified<EntityID> + Eq + Clone>
-    AbstractSemigroup<Additive> for EntityMap<A>
-{
-}
-
-impl<A: Positioned + Identified<EntityID> + Eq> Identity<Additive>
-    for EntityMap<A>
-{
-    fn identity() -> Self {
-        EntityMap::new()
-    }
-}
-
-impl<A: Positioned + Identified<EntityID> + Eq + Clone> AbstractMonoid<Additive>
-    for EntityMap<A>
-{
-}
-
-impl<A: PositionedMut> EntityMap<A> {
-    pub fn update_position(
-        &mut self,
-        entity_id: EntityID,
-        new_position: Position,
-    ) {
-        let mut old_pos = None;
-        if let Some(entity) = self.by_id.get_mut(&entity_id) {
-            if entity.position() == new_position {
-                return;
-            }
-            old_pos = Some(entity.position());
-            entity.set_position(new_position);
-        }
-
-        if let Some(p) = old_pos {
-            if let Some(es) = self.by_position.get_mut(&p) {
-                es.retain(|e| *e != entity_id);
-            }
-
-            self.by_position
-                .entry(new_position)
-                .or_insert_with(Vec::new)
-                .push(entity_id);
-        }
-    }
-}
-
-pub struct Drain<'a, A> {
-    map: &'a mut EntityMap<A>,
-    ids_iter: Box<dyn Iterator<Item = EntityID> + 'a>,
-}
-
-impl<A: Positioned + Identified<EntityID>> Iterator for Drain<'_, A> {
-    type Item = (EntityID, A);
-
-    fn next(&mut self) -> Option<Self::Item> {
-        self.ids_iter
-            .next()
-            .map(|eid| (eid, self.map.remove(eid).expect(BY_POS_INVARIANT)))
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::types::PositionedMut;
-    use proptest::prelude::*;
-    use proptest_derive::Arbitrary;
-
-    #[derive(Debug, Arbitrary, PartialEq, Eq, Clone)]
-    struct TestEntity {
-        _id: Option<EntityID>,
-        position: Position,
-        name: String,
-    }
-
-    impl Positioned for TestEntity {
-        fn position(&self) -> Position {
-            self.position
-        }
-    }
-
-    impl PositionedMut for TestEntity {
-        fn set_position(&mut self, pos: Position) {
-            self.position = pos
-        }
-    }
-
-    impl Identified<EntityID> for TestEntity {
-        fn opt_id(&self) -> Option<EntityID> {
-            self._id
-        }
-
-        fn set_id(&mut self, id: EntityID) {
-            self._id = Some(id);
-        }
-    }
-
-    fn gen_entity_map() -> BoxedStrategy<EntityMap<TestEntity>> {
-        any::<Vec<TestEntity>>()
-            .prop_map(|ents| {
-                ents.iter().cloned().collect::<EntityMap<TestEntity>>()
-            })
-            .boxed()
-    }
-
-    proptest! {
-        #![proptest_config(ProptestConfig::with_cases(10))]
-
-        #[test]
-        fn test_entity_map_len(items: Vec<TestEntity>) {
-            let mut map = EntityMap::new();
-            assert_eq!(map.len(), 0);
-            for ent in &items {
-                map.insert(ent.clone());
-            }
-            assert_eq!(map.len(), items.len());
-        }
-
-        #[test]
-        fn test_entity_map_getset(
-            mut em in gen_entity_map(),
-            ent: TestEntity
-        ) {
-            em.insert(ent.clone());
-            assert!(em.at(ent.position).iter().any(|e| e.name == ent.name))
-        }
-
-        #[test]
-        fn test_entity_map_set_iter_contains(
-            mut em in gen_entity_map(),
-            ent: TestEntity
-        ) {
-            em.insert(ent.clone());
-            assert!(em.entities().any(|e| e.name == ent.name))
-        }
-
-        #[test]
-        fn test_update_position(
-            mut em in gen_entity_map(),
-            ent: TestEntity,
-            new_position: Position,
-        ) {
-            let original_position = ent.position();
-            let entity_id = em.insert(ent.clone());
-            em.update_position(entity_id, new_position);
-
-            if new_position != original_position {
-                assert!(em.at(original_position).iter().all(|e| e.name != ent.name));
-            }
-            assert_eq!(
-                em.get(entity_id).map(|e| e.position()),
-                Some(new_position)
-            );
-            assert!(
-                em.at(new_position).iter().map(
-                    |e| e.name.clone()).any(|en| en == ent.name),
-            )
-        }
-
-        #[test]
-        fn test_remove_all_at(
-            mut em in gen_entity_map(),
-            pos: Position,
-        ) {
-            em.remove_all_at(pos);
-            assert_eq!(em.at(pos).len(), 0);
-        }
-
-        #[test]
-        fn test_entity_map_semigroup_laws(
-            em1 in gen_entity_map(),
-            em2 in gen_entity_map(),
-            em3 in gen_entity_map(),
-        ) {
-            assert!(AbstractSemigroup::prop_is_associative((em1, em2, em3)));
-        }
-
-        fn test_entity_map_monoid_laws(
-            em in gen_entity_map(),
-        ) {
-            assert!(
-                AbstractMonoid::prop_operating_identity_element_is_noop((em,))
-            );
-        }
-
-        #[test]
-        fn test_entity_map_append(
-            mut target in gen_entity_map(),
-            mut source in gen_entity_map(),
-        ) {
-            let orig_target = target.clone();
-            let orig_source = source.clone();
-
-            target.append(&mut source);
-            target.check_invariants();
-
-            assert_eq!(source, EntityMap::new());
-
-            for ent in orig_source.entities() {
-                assert!(
-                    target.at(ent.position()).iter().any(|e| e.name == ent.name)
-                );
-            }
-
-            for ent in orig_target.entities() {
-                assert!(
-                    target.at(ent.position()).iter().any(|e| e.name == ent.name)
-                );
-            }
-        }
-    }
-}
diff --git a/src/types/menu.rs b/src/types/menu.rs
deleted file mode 100644
index 63abc837788e..000000000000
--- a/src/types/menu.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-use crate::types::Dimensions;
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct MenuInfo {
-    pub prompt: String,
-    pub options: Vec<String>,
-}
-
-impl MenuInfo {
-    pub fn new(prompt: String, options: Vec<String>) -> Self {
-        MenuInfo { prompt, options }
-    }
-
-    /// Returns the inner dimensions of a box necessary to draw this menu. Will
-    /// not trim either dimension to the size of the terminal
-    pub fn dimensions(&self) -> Dimensions {
-        Dimensions {
-            w: self
-                .options
-                .iter()
-                .map(|s| s.len())
-                .max()
-                .unwrap_or(0)
-                .max(self.prompt.len()) as u16
-                + 4,
-            h: self.options.len() as u16
-                + if self.prompt.is_empty() { 0 } else { 2 }
-                + 4,
-        }
-    }
-}
diff --git a/src/types/mod.rs b/src/types/mod.rs
deleted file mode 100644
index d417e873d8ca..000000000000
--- a/src/types/mod.rs
+++ /dev/null
@@ -1,504 +0,0 @@
-#![allow(clippy::unit_arg)]
-#![allow(clippy::identity_conversion)]
-
-use std::cmp::max;
-use std::cmp::Ordering;
-use std::ops;
-use std::rc::Rc;
-
-pub mod collision;
-pub mod command;
-pub mod direction;
-pub mod entity_map;
-pub mod menu;
-
-pub use collision::Collision;
-pub use direction::Direction;
-pub use direction::Direction::*;
-use proptest_derive::Arbitrary;
-use termion::cursor;
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary)]
-pub struct Dimensions {
-    #[proptest(strategy = "std::ops::Range::<u16>::from(0..100)")]
-    pub w: u16,
-
-    #[proptest(strategy = "std::ops::Range::<u16>::from(0..100)")]
-    pub h: u16,
-}
-
-pub const ZERO_DIMENSIONS: Dimensions = Dimensions { w: 0, h: 0 };
-pub const UNIT_DIMENSIONS: Dimensions = Dimensions { w: 1, h: 1 };
-
-impl Default for Dimensions {
-    fn default() -> Self {
-        Dimensions { w: 80, h: 20 }
-    }
-}
-
-impl ops::Sub<Dimensions> for Dimensions {
-    type Output = Dimensions;
-    fn sub(self, dims: Dimensions) -> Dimensions {
-        Dimensions {
-            w: self.w - dims.w,
-            h: self.h - dims.h,
-        }
-    }
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary)]
-pub struct BoundingBox {
-    pub dimensions: Dimensions,
-    pub position: Position,
-}
-
-impl BoundingBox {
-    pub fn at_origin(dimensions: Dimensions) -> BoundingBox {
-        BoundingBox {
-            dimensions,
-            position: ORIGIN,
-        }
-    }
-
-    pub fn from_corners(
-        top_left: Position,
-        lower_right: Position,
-    ) -> BoundingBox {
-        BoundingBox {
-            position: top_left,
-            dimensions: Dimensions {
-                w: (lower_right.x - top_left.x) as u16,
-                h: (lower_right.y - top_left.y) as u16,
-            },
-        }
-    }
-
-    pub fn lr_corner(self) -> Position {
-        self.position
-            + (Position {
-                x: self.dimensions.w as i16,
-                y: self.dimensions.h as i16,
-            })
-    }
-
-    pub fn ll_corner(self) -> Position {
-        self.position
-            + (Position {
-                x: 0,
-                y: self.dimensions.h as i16,
-            })
-    }
-
-    /// Returns a bounding box representing the *inside* of this box if it was
-    /// drawn on the screen.
-    pub fn inner(self) -> BoundingBox {
-        self + UNIT_POSITION - UNIT_DIMENSIONS - UNIT_DIMENSIONS
-    }
-
-    /// Moves the top right corner of the bounding box by the offset specified
-    /// by the given position, keeping the lower right corner in place
-    pub fn move_tr_corner(self, offset: Position) -> BoundingBox {
-        self + offset
-            - Dimensions {
-                w: offset.x as u16,
-                h: offset.y as u16,
-            }
-    }
-}
-
-impl ops::Add<Position> for BoundingBox {
-    type Output = BoundingBox;
-    fn add(self, pos: Position) -> BoundingBox {
-        BoundingBox {
-            position: self.position + pos,
-            ..self
-        }
-    }
-}
-
-impl ops::Sub<Dimensions> for BoundingBox {
-    type Output = BoundingBox;
-    fn sub(self, dims: Dimensions) -> BoundingBox {
-        BoundingBox {
-            dimensions: self.dimensions - dims,
-            ..self
-        }
-    }
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary, Hash, Ord)]
-pub struct Position {
-    /// x (horizontal) position
-    #[proptest(strategy = "std::ops::Range::<i16>::from(0..100)")]
-    pub x: i16,
-
-    #[proptest(strategy = "std::ops::Range::<i16>::from(0..100)")]
-    /// y (vertical) position
-    pub y: i16,
-}
-
-pub fn pos(x: i16, y: i16) -> Position {
-    Position { x, y }
-}
-
-pub const ORIGIN: Position = Position { x: 0, y: 0 };
-pub const UNIT_POSITION: Position = Position { x: 1, y: 1 };
-
-impl Position {
-    /// Returns true if this position exists within the bounds of the given box,
-    /// inclusive
-    pub fn within(self, b: BoundingBox) -> bool {
-        (self > b.position - UNIT_POSITION) && self < (b.lr_corner())
-    }
-
-    /// Returns a sequence of ASCII escape characters for moving the cursor to
-    /// this Position
-    pub fn cursor_goto(self) -> cursor::Goto {
-        // + 1 because Goto is 1-based, but position is 0-based
-        cursor::Goto(self.x as u16 + 1, self.y as u16 + 1)
-    }
-
-    /// Converts this position to the number of `Tiles` away from the origin it
-    /// represents. Usually done after subtracting two positions. Gives distance
-    /// as the crow flies
-    pub fn as_tiles(self) -> Tiles {
-        Tiles(max(self.x.abs(), self.y.abs()).into())
-    }
-}
-
-impl PartialOrd for Position {
-    fn partial_cmp(&self, other: &Position) -> Option<Ordering> {
-        if self.x == other.x && self.y == other.y {
-            Some(Ordering::Equal)
-        } else if self.x > other.x && self.y > other.y {
-            Some(Ordering::Greater)
-        } else if self.x < other.x && self.y < other.y {
-            Some(Ordering::Less)
-        } else {
-            None
-        }
-    }
-}
-
-/// Implements (bounded) addition of a Dimension to a position.
-///
-/// # Examples
-///
-/// ```
-/// let pos = Position { x: 1, y: 10 }
-///
-/// let left_pos = pos + Direction::Left
-/// assert_eq!(left, Position { x: 0, y: 10 })
-///
-/// let right_pos = pos + Direction::Right
-/// assert_eq!(right_pos, Position { x: 0, y: 10 })
-/// ```
-#[allow(clippy::suspicious_arithmetic_impl)]
-impl ops::Add<Direction> for Position {
-    type Output = Position;
-    fn add(self, dir: Direction) -> Position {
-        match dir {
-            Left => {
-                if self.x > std::i16::MIN {
-                    Position {
-                        x: self.x - 1,
-                        ..self
-                    }
-                } else {
-                    self
-                }
-            }
-            Right => {
-                if self.x < std::i16::MAX {
-                    Position {
-                        x: self.x + 1,
-                        ..self
-                    }
-                } else {
-                    self
-                }
-            }
-            Up => {
-                if self.y > std::i16::MIN {
-                    Position {
-                        y: self.y - 1,
-                        ..self
-                    }
-                } else {
-                    self
-                }
-            }
-            Down => {
-                if self.y < std::i16::MAX {
-                    Position {
-                        y: self.y + 1,
-                        ..self
-                    }
-                } else {
-                    self
-                }
-            }
-            UpLeft => self + Up + Left,
-            UpRight => self + Up + Right,
-            DownLeft => self + Down + Left,
-            DownRight => self + Down + Right,
-        }
-    }
-}
-
-impl ops::Add<Position> for Position {
-    type Output = Position;
-    fn add(self, pos: Position) -> Position {
-        Position {
-            x: self.x + pos.x,
-            y: self.y + pos.y,
-        }
-    }
-}
-
-impl ops::Sub<Position> for Position {
-    type Output = Position;
-    fn sub(self, pos: Position) -> Position {
-        Position {
-            x: self.x - pos.x,
-            y: self.y - pos.y,
-        }
-    }
-}
-
-impl Positioned for Position {
-    fn position(&self) -> Position {
-        *self
-    }
-}
-
-pub trait Positioned {
-    fn x(&self) -> i16 {
-        self.position().x
-    }
-
-    fn y(&self) -> i16 {
-        self.position().y
-    }
-
-    fn position(&self) -> Position {
-        Position {
-            x: self.x(),
-            y: self.y(),
-        }
-    }
-}
-
-pub trait PositionedMut: Positioned {
-    fn set_position(&mut self, pos: Position);
-}
-
-// impl<A, I> Positioned for A where A : Deref<Target = I>, I: Positioned {
-//     fn position(&self) -> Position {
-//         self.position()
-//     }
-// }
-
-impl<T: Positioned> Positioned for Box<T> {
-    fn position(&self) -> Position {
-        (**self).position()
-    }
-}
-
-impl<'a, T: Positioned> Positioned for &'a T {
-    fn position(&self) -> Position {
-        (**self).position()
-    }
-}
-
-impl<'a, T: Positioned> Positioned for &'a mut T {
-    fn position(&self) -> Position {
-        (**self).position()
-    }
-}
-
-impl<'a, T: Positioned> Positioned for Rc<T> {
-    fn position(&self) -> Position {
-        (**self).position()
-    }
-}
-
-impl<'a, T: PositionedMut> PositionedMut for &'a mut T {
-    fn set_position(&mut self, pos: Position) {
-        (**self).set_position(pos)
-    }
-}
-
-#[macro_export]
-macro_rules! positioned {
-    ($name:ident) => {
-        positioned!($name, position);
-    };
-    ($name:ident, $attr:ident) => {
-        impl $crate::types::Positioned for $name {
-            fn position(&self) -> $crate::types::Position {
-                self.$attr
-            }
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! positioned_mut {
-    ($name:ident) => {
-        positioned_mut!($name, position);
-    };
-    ($name:ident, $attr:ident) => {
-        impl crate::types::PositionedMut for $name {
-            fn set_position(&mut self, pos: $crate::types::Position) {
-                self.$attr = pos;
-            }
-        }
-    };
-}
-
-/// A number of ticks
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary)]
-pub struct Ticks(pub u16);
-
-/// A number of tiles
-///
-/// Expressed in terms of a float to allow moving partial tiles in a number of
-/// ticks
-#[derive(Clone, Copy, Debug, PartialEq, Arbitrary)]
-pub struct Tiles(pub f32);
-
-/// The speed of an entity, expressed in ticks per tile
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary, Deserialize)]
-#[serde(transparent)]
-pub struct Speed(pub u32);
-
-impl Speed {
-    /// Returns the number of tiles that would be moved in the given number of
-    /// ticks at this speed
-    pub fn ticks_to_tiles(self, ticks: Ticks) -> Tiles {
-        Tiles(f32::from(ticks.0) / self.0 as f32)
-    }
-
-    /// Returns the number of ticks required to move the given number of tiles
-    /// at this speed
-    pub fn tiles_to_ticks(self, tiles: Tiles) -> Ticks {
-        Ticks(tiles.0 as u16 * self.0 as u16)
-    }
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary)]
-pub struct Neighbors<A> {
-    pub top_left: A,
-    pub top: A,
-    pub top_right: A,
-    pub left: A,
-    pub right: A,
-    pub bottom_left: A,
-    pub bottom: A,
-    pub bottom_right: A,
-}
-
-impl Neighbors<Position> {
-    fn of_position(pos: Position) -> Self {
-        Neighbors {
-            top_left: pos + Direction::UpLeft,
-            top: pos + Direction::Up,
-            top_right: pos + Direction::UpRight,
-            left: pos + Direction::Left,
-            right: pos + Direction::Right,
-            bottom_left: pos + Direction::DownLeft,
-            bottom: pos + Direction::Down,
-            bottom_right: pos + Direction::DownRight,
-        }
-    }
-}
-
-impl<A> Neighbors<A> {
-    /// it's a functor, yo
-    pub fn map<B, F: Fn(&A) -> B>(&self, f: F) -> Neighbors<B> {
-        Neighbors {
-            top_left: f(&self.top_left),
-            top: f(&self.top),
-            top_right: f(&self.top_right),
-            left: f(&self.left),
-            right: f(&self.right),
-            bottom_left: f(&self.bottom_left),
-            bottom: f(&self.bottom),
-            bottom_right: f(&self.bottom_right),
-        }
-    }
-}
-
-impl<A> Neighbors<Vec<A>> {
-    pub fn mapmap<B, F: Fn(&A) -> B>(&self, f: &F) -> Neighbors<Vec<B>> {
-        self.map(|xs| xs.iter().map(f).collect())
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    #![allow(clippy::unnecessary_operation)]
-    use super::*;
-    use proptest::prelude::*;
-
-    proptest! {
-        #[test]
-        fn position_partialord_lt_transitive(
-            a: Position,
-            b: Position,
-            c: Position
-        ) {
-            if a < b && b < c {
-                assert!(a < c)
-            }
-        }
-
-        #[test]
-        fn position_partialord_eq_transitive(
-            a: Position,
-            b: Position,
-            c: Position
-        ) {
-            if a == b && b == c {
-                assert!(a == c)
-            }
-        }
-
-        #[test]
-        fn position_partialord_gt_transitive(
-            a: Position,
-            b: Position,
-            c: Position,
-        ) {
-            if a > b && b > c {
-                assert!(a > c)
-            }
-        }
-
-        #[test]
-        fn position_partialord_antisymmetric(a: Position, b: Position) {
-            if a < b {
-                assert!(!(a > b))
-            } else if a > b {
-                assert!(!(a < b))
-            }
-        }
-
-        #[test]
-        fn test_position_plus_dimension_as_tiles_monoid_action(
-            pos: Position,
-            dir: Direction,
-        ) {
-            prop_assume!(pos.y > 0 && pos.x > 0);
-            assert_eq!(((pos + dir) - pos).as_tiles(), Tiles(1.0));
-        }
-    }
-
-    #[test]
-    fn test_position_as_tiles() {
-        assert_eq!(pos(0, 0).as_tiles(), Tiles(0.0));
-        assert_eq!(pos(1, 1).as_tiles(), Tiles(1.0));
-        assert_eq!(pos(1, 2).as_tiles(), Tiles(2.0));
-    }
-}
diff --git a/src/util/mod.rs b/src/util/mod.rs
deleted file mode 100644
index dd5087a55558..000000000000
--- a/src/util/mod.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#[macro_use]
-pub mod static_cfg;
-#[macro_use]
-pub mod template;
-pub mod promise;
-#[macro_use]
-pub mod trait_impls;
diff --git a/src/util/promise.rs b/src/util/promise.rs
deleted file mode 100644
index 22f1e8b47f58..000000000000
--- a/src/util/promise.rs
+++ /dev/null
@@ -1,160 +0,0 @@
-use std::future::Future;
-use std::pin::Pin;
-use std::sync::{Arc, RwLock};
-use std::task::{Context, Poll, Waker};
-
-type Waiter<Env, T> = Box<dyn Fn(&mut Env, &T)>;
-
-pub struct Promise<Env, T> {
-    inner: Arc<RwLock<Inner<T>>>,
-    waiters: Arc<RwLock<Vec<Waiter<Env, T>>>>,
-}
-
-pub struct Complete<T> {
-    inner: Arc<RwLock<Inner<T>>>,
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct Cancelled;
-
-struct Inner<T> {
-    value: Option<Arc<T>>,
-    waker: Option<Waker>,
-}
-
-pub fn promise<Env, T>() -> (Complete<T>, Promise<Env, T>) {
-    let inner = Arc::new(RwLock::new(Inner {
-        value: None,
-        waker: None,
-    }));
-    let promise = Promise {
-        inner: inner.clone(),
-        waiters: Arc::new(RwLock::new(Vec::new())),
-    };
-    let complete = Complete { inner };
-    (complete, promise)
-}
-
-impl<T> Complete<T> {
-    pub fn fulfill(&self, val: T) {
-        let mut inner = self.inner.write().unwrap();
-        inner.value = Some(Arc::new(val));
-        if let Some(waker) = inner.waker.take() {
-            waker.wake()
-        }
-    }
-}
-
-impl<T> Complete<Result<T, Cancelled>> {
-    pub fn cancel(&mut self) {
-        self.fulfill(Err(Cancelled))
-    }
-}
-
-impl<E, T> Complete<Result<T, E>> {
-    pub fn ok(&mut self, val: T) {
-        self.fulfill(Ok(val))
-    }
-
-    pub fn err(&mut self, e: E) {
-        self.fulfill(Err(e))
-    }
-}
-
-impl<Env, T> Promise<Env, T> {
-    pub fn on_fulfill<F: Fn(&mut Env, &T) + 'static>(&mut self, f: F) {
-        let mut waiters = self.waiters.write().unwrap();
-        waiters.push(Box::new(f));
-    }
-}
-
-impl<Env, T> Promise<Env, Result<T, Cancelled>> {
-    pub fn on_cancel<F: Fn(&mut Env) + 'static>(&mut self, f: F) {
-        self.on_err(move |env, _| f(env))
-    }
-}
-
-impl<Env, E, T> Promise<Env, Result<T, E>> {
-    pub fn on_ok<F: Fn(&mut Env, &T) + 'static>(&mut self, f: F) {
-        self.on_fulfill(move |env, r| {
-            if let Ok(val) = r {
-                f(env, val)
-            }
-        })
-    }
-
-    pub fn on_err<F: Fn(&mut Env, &E) + 'static>(&mut self, f: F) {
-        self.on_fulfill(move |env, r| {
-            if let Err(e) = r {
-                f(env, e)
-            }
-        })
-    }
-}
-
-pub trait Give<Env> {
-    fn give(&self, env: &mut Env) -> bool;
-}
-
-impl<Env, T> Give<Env> for Promise<Env, T> {
-    fn give(&self, env: &mut Env) -> bool {
-        let inner = self.inner.read().unwrap();
-        if let Some(value) = &inner.value {
-            let mut waiters = self.waiters.write().unwrap();
-            for waiter in waiters.iter() {
-                waiter(env, value);
-            }
-            waiters.clear();
-            true
-        } else {
-            false
-        }
-    }
-}
-
-impl<Env, T> Clone for Promise<Env, T> {
-    fn clone(&self) -> Self {
-        Promise {
-            inner: self.inner.clone(),
-            waiters: self.waiters.clone(),
-        }
-    }
-}
-
-impl<Env, P: Give<Env>> Give<Env> for &P {
-    fn give(&self, env: &mut Env) -> bool {
-        (*self).give(env)
-    }
-}
-
-impl<Env, T> Future for Promise<Env, T> {
-    type Output = Arc<T>;
-    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
-        let mut inner = self.inner.write().unwrap();
-        match inner.value {
-            Some(ref v) => Poll::Ready(v.clone()),
-            None => {
-                inner.waker = Some(cx.waker().clone());
-                Poll::Pending
-            }
-        }
-    }
-}
-
-pub struct Promises<'a, Env> {
-    ps: Vec<Box<dyn Give<Env> + 'a>>,
-}
-
-impl<'a, Env> Promises<'a, Env> {
-    pub fn new() -> Self {
-        Promises { ps: Vec::new() }
-    }
-
-    pub fn push(&mut self, p: Box<dyn Give<Env> + 'a>) {
-        self.ps.push(p);
-    }
-
-    pub fn give_all(&mut self, env: &mut Env) {
-        self.ps.retain(|p| !p.give(env));
-    }
-}
diff --git a/src/util/static_cfg.rs b/src/util/static_cfg.rs
deleted file mode 100644
index b20456fb3bd4..000000000000
--- a/src/util/static_cfg.rs
+++ /dev/null
@@ -1,147 +0,0 @@
-use include_dir::Dir;
-use serde::de;
-
-macro_rules! __static_cfg_include {
-    (toml_file, $filename:expr) => {
-        include_str!($filename)
-    };
-    (toml_dir, $filename:expr) => {
-        include_dir!($filename)
-    };
-    (json_file, $filename:expr) => {
-        include_str!($filename)
-    };
-    (json_dir, $filename:expr) => {
-        include_dir!($filename)
-    };
-    (cfg_dir, $filename:expr) => {
-        include_dir!($filename)
-    };
-}
-
-macro_rules! __static_cfg_type {
-    (toml_file) => (&'static str);
-    (json_file) => (&'static str);
-    (toml_dir) => (include_dir::Dir<'static>);
-    (json_dir) => (include_dir::Dir<'static>);
-    (cfg_dir) => (include_dir::Dir<'static>);
-}
-
-macro_rules! __static_cfg_parse {
-    (toml_file, $e:expr) => {
-        toml::from_str($e).unwrap()
-    };
-
-    (json_file, $e:expr) => {
-        serde_json::from_str($e).unwrap()
-    };
-
-    (toml_dir, $e:expr) => {
-        crate::util::static_cfg::parse_toml_dir($e)
-    };
-
-    (json_dir, $e:expr) => {
-        crate::util::static_cfg::parse_json_dir($e)
-    };
-
-    (cfg_dir, $e:expr) => {
-        crate::util::static_cfg::parse_cfg_dir($e);
-    };
-}
-
-macro_rules! __static_cfg_inner {
-    ($(#[$attr:meta])* ($($vis:tt)*) static ref $N:ident : $T:ty = $kind:ident($filename:expr); $($t:tt)*) => {
-        // static RAW: &'static str = __static_cfg_include!($kind, $filename);
-        static RAW: __static_cfg_type!($kind) = __static_cfg_include!($kind, $filename);
-        lazy_static! {
-            $(#[$attr])* static ref $N: $T = __static_cfg_parse!($kind, RAW);
-        }
-
-        static_cfg!($($t)*);
-    }
-}
-
-#[macro_export]
-macro_rules! static_cfg {
-    ($(#[$attr:meta])* static ref $N:ident : $T:ty = $kind:ident($filename:expr); $($t:tt)*) => {
-        __static_cfg_inner!($(#[$attr])* () static ref $N : $T = $kind($filename); $($t)*);
-    };
-
-    ($(#[$attr:meta])* pub static ref $N:ident : $T:ty = $kind:ident($filename:expr); $($t:tt)*) => {
-        __static_cfg_inner!($(#[$attr])* (pub) static ref $N : $T = $kind($filename); $($t)*);
-    };
-
-    ($(#[$attr:meta])* pub ($($vis:tt)+) static ref $N:ident : $T:ty = $kind:ident($filename:expr); $($t:tt)*) => {
-        __static_cfg_inner!($(#[$attr])* (pub ($($vis)+)) static ref $N : $T = $kind($filename); $($t)*);
-    };
-
-    () => ()
-}
-
-pub fn parse_cfg_dir<'a, T>(d: Dir<'a>) -> Vec<T>
-where
-    T: de::Deserialize<'a>,
-{
-    d.files()
-        .iter()
-        .filter_map(|f| {
-            let path = f.path();
-            let contents = f.contents_utf8().unwrap();
-            match path.extension().and_then(|e| e.to_str()) {
-                Some("toml") => {
-                    Some(toml::from_str(contents).unwrap_or_else(|e| {
-                        panic!(
-                            "Error parsing TOML file {}: {}",
-                            path.display(),
-                            e
-                        )
-                    }))
-                }
-                Some("json") => {
-                    Some(serde_json::from_str(contents).unwrap_or_else(|e| {
-                        panic!(
-                            "Error parsing JSON file {}: {}",
-                            path.display(),
-                            e
-                        )
-                    }))
-                }
-                // > YAML currently does not support zero-copy deserialization
-                // Some("yaml") => {
-                //     Some(serde_yaml::from_str(contents).unwrap_or_else(|e| {
-                //         panic!(
-                //             "Error parsing YAML file {}: {}",
-                //             path.display(),
-                //             e
-                //         )
-                //     }))
-                // }
-                _ => None,
-            }
-        })
-        .collect()
-}
-
-pub fn parse_toml_dir<'a, T>(d: Dir<'a>) -> Vec<T>
-where
-    T: de::Deserialize<'a>,
-{
-    d.files()
-        .iter()
-        .map(|f| {
-            toml::from_str(f.contents_utf8().unwrap()).unwrap_or_else(|e| {
-                panic!("Error parsing TOML file {}: {}", f.path, e)
-            })
-        })
-        .collect()
-}
-
-pub fn parse_json_dir<'a, T>(d: Dir<'a>) -> Vec<T>
-where
-    T: de::Deserialize<'a>,
-{
-    d.files()
-        .iter()
-        .map(|f| serde_json::from_str(f.contents_utf8().unwrap()).unwrap())
-        .collect()
-}
diff --git a/src/util/template.rs b/src/util/template.rs
deleted file mode 100644
index bb77f9b4d610..000000000000
--- a/src/util/template.rs
+++ /dev/null
@@ -1,362 +0,0 @@
-use nom::combinator::rest;
-use nom::error::ErrorKind;
-use nom::{Err, IResult};
-use std::collections::HashMap;
-use std::fmt::{self, Display};
-use std::marker::PhantomData;
-
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct Path<'a> {
-    head: &'a str,
-    tail: Vec<&'a str>,
-}
-
-impl<'a> Path<'a> {
-    fn new(head: &'a str, tail: Vec<&'a str>) -> Self {
-        Path { head, tail }
-    }
-}
-
-impl<'a> Display for Path<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{}", self.head)?;
-        for part in &self.tail {
-            write!(f, ".{}", part)?;
-        }
-        Ok(())
-    }
-}
-
-// named!(path_ident, map_res!(is_not!(".}"), std::str::from_utf8));
-fn path_ident<'a>(input: &'a str) -> IResult<&'a str, &'a str> {
-    take_till!(input, |c| c == '.' || c == '}')
-}
-
-fn path<'a>(input: &'a str) -> IResult<&'a str, Path<'a>> {
-    map!(
-        input,
-        tuple!(
-            path_ident,
-            many0!(complete!(preceded!(char!('.'), path_ident)))
-        ),
-        |(h, t)| Path::new(h, t)
-    )
-}
-
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub enum TemplateToken<'a> {
-    Literal(&'a str),
-    Substitution(Path<'a>),
-}
-
-fn token_substitution<'a>(
-    input: &'a str,
-) -> IResult<&'a str, TemplateToken<'a>> {
-    map!(
-        input,
-        delimited!(tag!("{{"), path, tag!("}}")),
-        TemplateToken::Substitution
-    )
-}
-
-fn template_token<'a>(input: &'a str) -> IResult<&'a str, TemplateToken<'a>> {
-    alt!(
-        input,
-        token_substitution
-            | map!(
-                alt!(complete!(take_until!("{{")) | complete!(rest)),
-                TemplateToken::Literal
-            )
-    )
-}
-
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct Template<'a> {
-    tokens: Vec<TemplateToken<'a>>,
-}
-
-impl<'a> Template<'a> {
-    pub fn new(tokens: Vec<TemplateToken<'a>>) -> Self {
-        Template { tokens }
-    }
-}
-
-pub struct TemplateVisitor<'a> {
-    marker: PhantomData<fn() -> Template<'a>>,
-}
-
-impl<'a> TemplateVisitor<'a> {
-    pub fn new() -> Self {
-        TemplateVisitor {
-            marker: PhantomData,
-        }
-    }
-}
-
-impl<'a> serde::de::Visitor<'a> for TemplateVisitor<'a> {
-    type Value = Template<'a>;
-
-    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-        formatter.write_str("a valid template string")
-    }
-
-    fn visit_borrowed_str<E: serde::de::Error>(
-        self,
-        v: &'a str,
-    ) -> Result<Self::Value, E> {
-        Template::parse(v).map_err(|_| {
-            serde::de::Error::invalid_value(
-                serde::de::Unexpected::Str(v),
-                &"a valid template string",
-            )
-        })
-    }
-}
-
-impl<'a> serde::Deserialize<'a> for Template<'a> {
-    fn deserialize<D: serde::Deserializer<'a>>(
-        deserializer: D,
-    ) -> Result<Self, D::Error> {
-        deserializer.deserialize_str(TemplateVisitor::new())
-    }
-}
-
-impl<'a> Template<'a> {
-    pub fn parse(
-        input: &'a str,
-    ) -> Result<Template<'a>, Err<(&'a str, ErrorKind)>> {
-        let (remaining, res) = template(input)?;
-        if !remaining.is_empty() {
-            unreachable!();
-        }
-        Ok(res)
-    }
-
-    pub fn format(
-        &self,
-        params: &TemplateParams<'a>,
-    ) -> Result<String, TemplateError<'a>> {
-        use TemplateToken::*;
-        let mut res = String::new();
-        for token in &self.tokens {
-            match token {
-                Literal(s) => res.push_str(s),
-                Substitution(p) => match params.get(p.clone()) {
-                    Some(s) => res.push_str(s),
-                    None => return Err(TemplateError::MissingParam(p.clone())),
-                },
-            }
-        }
-        Ok(res)
-    }
-}
-
-#[derive(Debug, PartialEq, Eq)]
-pub enum TemplateError<'a> {
-    MissingParam(Path<'a>),
-}
-
-impl<'a> Display for TemplateError<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use TemplateError::*;
-        match self {
-            MissingParam(path) => {
-                write!(f, "Missing template parameter: {}", path)
-            }
-        }
-    }
-}
-
-#[derive(Debug, PartialEq, Eq)]
-pub enum TemplateParams<'a> {
-    Direct(&'a str),
-    Nested(HashMap<&'a str, TemplateParams<'a>>),
-}
-
-impl<'a> TemplateParams<'a> {
-    fn get(&self, path: Path<'a>) -> Option<&'a str> {
-        use TemplateParams::*;
-        match self {
-            Direct(_) => None,
-            Nested(m) => m.get(path.head).and_then(|next| {
-                if path.tail.is_empty() {
-                    match next {
-                        Direct(s) => Some(*s),
-                        _ => None,
-                    }
-                } else {
-                    next.get(Path {
-                        head: path.tail[0],
-                        tail: path.tail[1..].to_vec(),
-                    })
-                }
-            }),
-        }
-    }
-}
-
-#[macro_export]
-macro_rules! template_params {
-    (@count $head: expr => $hv: tt, $($rest:tt)+) => { 1 + template_params!(@count $($rest)+) };
-    (@count $one:expr => $($ov: tt)*) => { 1 };
-    (@inner $ret: ident, ($key: expr => {$($v:tt)*}, $($r:tt)*)) => {
-        $ret.insert($key, template_params!({ $($v)* }));
-        template_params!(@inner $ret, ($($r)*));
-    };
-    (@inner $ret: ident, ($key: expr => $value: expr, $($r:tt)*)) => {
-        $ret.insert($key, template_params!($value));
-        template_params!(@inner $ret, ($($r)*));
-    };
-    (@inner $ret: ident, ()) => {};
-
-    ({ $($body: tt)* }) => {{
-        let _cap = template_params!(@count $($body)*);
-        let mut _m = ::std::collections::HashMap::with_capacity(_cap);
-        template_params!(@inner _m, ($($body)*));
-        TemplateParams::Nested(_m)
-    }};
-
-    ($direct:expr) => { TemplateParams::Direct($direct) };
-
-    () => { TemplateParams::Nested(::std::collections::HashMap::new()) };
-}
-
-fn template<'a>(input: &'a str) -> IResult<&'a str, Template<'a>> {
-    complete!(
-        input,
-        map!(many1!(complete!(template_token)), Template::new)
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn test_parse_path_ident() {
-        assert_eq!(path_ident("foo}}"), Ok(("}}", "foo")));
-        assert_eq!(path_ident("foo.bar}}"), Ok((".bar}}", "foo")));
-    }
-
-    #[test]
-    fn test_parse_path() {
-        assert_eq!(path("foo}}"), Ok(("}}", Path::new("foo", vec![]))));
-        assert_eq!(
-            path("foo.bar}}"),
-            Ok(("}}", Path::new("foo", vec!["bar"])))
-        );
-        assert_eq!(
-            path("foo.bar.baz}}"),
-            Ok(("}}", Path::new("foo", vec!["bar", "baz"])))
-        );
-    }
-
-    #[test]
-    fn test_parse_template_token() {
-        assert_eq!(
-            template_token("foo bar"),
-            Ok(("", TemplateToken::Literal("foo bar")))
-        );
-
-        assert_eq!(
-            template_token("foo bar {{baz}}"),
-            Ok(("{{baz}}", TemplateToken::Literal("foo bar ")))
-        );
-
-        assert_eq!(
-            template_token("{{baz}}"),
-            Ok((
-                "",
-                TemplateToken::Substitution(Path::new("baz", Vec::new()))
-            ))
-        );
-
-        assert_eq!(
-            template_token("{{baz}} foo bar"),
-            Ok((
-                " foo bar",
-                TemplateToken::Substitution(Path::new("baz", Vec::new()))
-            ))
-        );
-    }
-
-    #[test]
-    fn test_parse_template() {
-        assert_eq!(
-            template("foo bar"),
-            Ok((
-                "",
-                Template {
-                    tokens: vec![TemplateToken::Literal("foo bar")]
-                }
-            ))
-        );
-
-        assert_eq!(
-            template("foo bar {{baz}} qux"),
-            Ok((
-                "",
-                Template {
-                    tokens: vec![
-                        TemplateToken::Literal("foo bar "),
-                        TemplateToken::Substitution(Path::new(
-                            "baz",
-                            Vec::new()
-                        )),
-                        TemplateToken::Literal(" qux"),
-                    ]
-                }
-            ))
-        );
-    }
-
-    #[test]
-    fn test_template_params_literal() {
-        // trace_macros!(true);
-        let expected = template_params!({
-            "direct" => "hi",
-            "other" => "here",
-            "nested" => {
-                "one" => "1",
-                "two" => "2",
-                "double" => {
-                    "three" => "3",
-                },
-            },
-        });
-        // trace_macros!(false);
-        assert_eq!(
-            TemplateParams::Nested(hashmap! {
-                "direct" => TemplateParams::Direct("hi"),
-                "other" => TemplateParams::Direct("here"),
-                "nested" => TemplateParams::Nested(hashmap!{
-                    "one" => TemplateParams::Direct("1"),
-                    "two" => TemplateParams::Direct("2"),
-                    "double" => TemplateParams::Nested(hashmap!{
-                        "three" => TemplateParams::Direct("3"),
-                    })
-                })
-            }),
-            expected,
-        )
-    }
-
-    #[test]
-    fn test_format_template() {
-        assert_eq!(
-            "foo bar baz qux",
-            Template::parse("foo {{x}} {{y.z}} {{y.w.z}}")
-                .unwrap()
-                .format(&template_params!({
-                    "x" => "bar",
-                    "y" => {
-                        "z" => "baz",
-                        "w" => {
-                            "z" => "qux",
-                        },
-                    },
-                }))
-                .unwrap()
-        )
-    }
-}
diff --git a/src/util/trait_impls.rs b/src/util/trait_impls.rs
deleted file mode 100644
index ba15f7119d26..000000000000
--- a/src/util/trait_impls.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-macro_rules! ref_impl {
-    (impl<T: $traitb: ident $(+ $bound:ident)*> $traiti:ident for &T {
-        $($body:tt)*
-    }) => {
-        impl<'a, T: $traitb $(+ $bound)*> $traiti for &'a T {
-            $($body)*
-        }
-
-        impl<'a, T: $traitb $(+ $bound)*> $traiti for &'a mut T {
-            $($body)*
-        }
-
-        impl<T: $traitb $(+ $bound)*> $traiti for ::std::boxed::Box<T> {
-            $($body)*
-        }
-    };
-}