diff --git a/Cargo.lock b/Cargo.lock
index eb591c60a07865133a5e58915e359198eb087ea0..06d9efb9e0052fba15ef189d6a9526f0de92e10f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,5 +1,3 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
 [[package]]
 name = "aho-corasick"
 version = "0.7.3"
@@ -29,44 +27,44 @@ name = "atty"
 version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
- "termion 1.5.1 (git+https://gitlab.redox-os.org/redox-os/termion)",
+ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
+ "termion 1.5.2 (git+https://gitlab.redox-os.org/redox-os/termion)",
  "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "auto_enums"
-version = "0.5.5"
+version = "0.5.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "auto_enums_core 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "auto_enums_derive 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "auto_enums_core 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "auto_enums_derive 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "auto_enums_core"
-version = "0.5.5"
+version = "0.5.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "auto_enums_derive"
-version = "0.5.5"
+version = "0.5.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "derive_utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -82,8 +80,8 @@ dependencies = [
  "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
  "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -92,13 +90,13 @@ name = "backtrace-sys"
 version = "0.1.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "bitflags"
-version = "1.0.4"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -114,14 +112,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 [[package]]
 name = "calculate"
 version = "0.7.0"
-source = "git+https://gitlab.redox-os.org/redox-os/calc#62378ccbffc8f63ca4e8b36b728d273c71238a41"
+source = "git+https://gitlab.redox-os.org/redox-os/calc#48d847491f74f4324bc31bec008ec80374226eeb"
 dependencies = [
  "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "decimal 2.0.4 (git+https://github.com/alkis/decimal.git)",
  "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "liner 0.4.5 (git+https://gitlab.redox-os.org/redox-os/liner)",
- "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -132,7 +130,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "cc"
-version = "1.0.35"
+version = "1.0.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -147,7 +145,7 @@ 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.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.0.5 (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)",
@@ -159,7 +157,7 @@ name = "cloudabi"
 version = "0.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -171,10 +169,10 @@ dependencies = [
  "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "csv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "csv 1.0.7 (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)",
- "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -231,12 +229,12 @@ dependencies = [
 
 [[package]]
 name = "csv"
-version = "1.0.6"
+version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "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.90 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -253,12 +251,9 @@ name = "decimal"
 version = "2.0.4"
 source = "git+https://github.com/alkis/decimal.git#972c8547a0a76c7ad9a314e28a335aa57d46a543"
 dependencies = [
- "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
- "ord_subset 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -266,9 +261,9 @@ name = "derive_utils"
 version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.29 (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.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -281,10 +276,10 @@ name = "err-derive"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)",
  "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -294,7 +289,7 @@ version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -311,9 +306,9 @@ name = "failure_derive"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.29 (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.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)",
  "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -353,7 +348,7 @@ name = "ion-shell"
 version = "1.0.0-alpha"
 dependencies = [
  "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "auto_enums 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "auto_enums 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "calculate 0.7.0 (git+https://gitlab.redox-os.org/redox-os/calc)",
  "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "err-derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -365,12 +360,12 @@ dependencies = [
  "ion_lexers 0.1.0",
  "ion_sys 0.1.0",
  "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "liner 0.4.5 (git+https://gitlab.redox-os.org/redox-os/liner)",
  "object-pool 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "serial_test 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serial_test_derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "small 0.1.0 (git+https://gitlab.redox-os.org/redox-os/small)",
@@ -384,7 +379,7 @@ dependencies = [
 name = "ion_braces"
 version = "0.1.0"
 dependencies = [
- "auto_enums 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "auto_enums 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "permutate 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "small 0.1.0 (git+https://gitlab.redox-os.org/redox-os/small)",
  "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -394,7 +389,7 @@ dependencies = [
 name = "ion_builtins"
 version = "0.1.0"
 dependencies = [
- "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "calculate 0.7.0 (git+https://gitlab.redox-os.org/redox-os/calc)",
  "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "small 0.1.0 (git+https://gitlab.redox-os.org/redox-os/small)",
@@ -405,7 +400,7 @@ dependencies = [
 name = "ion_lexers"
 version = "0.1.0"
 dependencies = [
- "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -413,7 +408,7 @@ name = "ion_sys"
 version = "0.1.0"
 dependencies = [
  "errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
  "redox_syscall 0.1.54 (git+https://gitlab.redox-os.org/redox-os/syscall.git)",
  "users 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -428,7 +423,7 @@ dependencies = [
 
 [[package]]
 name = "itoa"
-version = "0.4.3"
+version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -451,14 +446,14 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "ryu 0.2.7 (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.2 (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.51"
+version = "0.2.54"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -467,7 +462,7 @@ version = "0.4.5"
 source = "git+https://gitlab.redox-os.org/redox-os/liner#c3bc46402ada277efd5048b2aaf67062fb2c8086"
 dependencies = [
  "bytecount 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "termion 1.5.1 (git+https://gitlab.redox-os.org/redox-os/termion)",
+ "termion 1.5.2 (git+https://gitlab.redox-os.org/redox-os/termion)",
  "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -485,7 +480,7 @@ name = "memchr"
 version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -500,35 +495,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "num"
-version = "0.1.42"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-complex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "num-bigint"
-version = "0.1.44"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "num-complex"
-version = "0.1.43"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -550,13 +542,12 @@ dependencies = [
 
 [[package]]
 name = "num-rational"
-version = "0.1.42"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -569,7 +560,7 @@ name = "num_cpus"
 version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -585,11 +576,6 @@ dependencies = [
  "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "ord_subset"
-version = "3.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "owning_ref"
 version = "0.4.0"
@@ -612,7 +598,7 @@ name = "parking_lot_core"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -626,7 +612,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "proc-macro2"
-version = "0.4.27"
+version = "0.4.29"
 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)",
@@ -637,19 +623,7 @@ name = "quote"
 version = "0.6.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "rand"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_core 0.3.1 (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)",
+ "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -658,12 +632,12 @@ version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.54 (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.3 (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)",
@@ -710,10 +684,10 @@ dependencies = [
 
 [[package]]
 name = "rand_jitter"
-version = "0.1.3"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.54 (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)",
 ]
@@ -725,7 +699,7 @@ 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.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.54 (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)",
@@ -774,7 +748,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -801,7 +775,7 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.1.5"
+version = "1.1.6"
 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)",
@@ -821,12 +795,7 @@ dependencies = [
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "rustc-serialize"
-version = "0.3.24"
+version = "0.1.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -839,7 +808,7 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "0.2.7"
+version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -878,9 +847,9 @@ name = "serde_derive"
 version = "1.0.90"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.29 (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.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -888,8 +857,8 @@ name = "serde_json"
 version = "1.0.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "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.90 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -907,7 +876,7 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -948,10 +917,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "syn"
-version = "0.15.30"
+version = "0.15.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.29 (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)",
 ]
@@ -961,18 +930,18 @@ name = "synstructure"
 version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.29 (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.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.33 (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 = "termion"
-version = "1.5.1"
-source = "git+https://gitlab.redox-os.org/redox-os/termion#5992932c65a7c1ece7e46226957a386793486175"
+version = "1.5.2"
+source = "git+https://gitlab.redox-os.org/redox-os/termion#a69af17888f040b6e9baf344fde984e7f3b60ee6"
 dependencies = [
- "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.54 (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 (git+https://gitlab.redox-os.org/redox-os/syscall.git)",
  "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1036,7 +1005,7 @@ name = "users"
 version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1106,18 +1075,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
 "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 auto_enums 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5999c1e1bd0972da60a4a58d0eef0d183dab8b787a1fde0e94e9a995f6275928"
-"checksum auto_enums_core 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "76cde7b6c90dbc5499dc58777e4fd3af08124ac8c26778044c10934e41a1e26e"
-"checksum auto_enums_derive 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b14b1eac6d98375d2f325c86085dc75705fb27b95cce9a5ff232ee74d3813fa8"
+"checksum auto_enums 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "00c047f9ba81ba9c4b4a6ed9382ca626b43fb8330bfe15d756ec12e19f41d954"
+"checksum auto_enums_core 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "5e7ab8be59b29ad82be4b94288ad6e5d52f95d578bd9399adb20e1ae46253146"
+"checksum auto_enums_derive 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "5a6414b77b31d0a78417dcfb6288068d4137c8a9ba3debc8ddacf44b1b54ca45"
 "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
 "checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637"
 "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
-"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
+"checksum bitflags 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bd1fa8ad26490b0a5cfec99089952250301b6716cdeaa7c9ab229598fb82ab66"
 "checksum bytecount 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f861d9ce359f56dbcb6e0c2a1cb84e52ad732cadb57b806adeb3c7668caccbd8"
 "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
 "checksum calculate 0.7.0 (git+https://gitlab.redox-os.org/redox-os/calc)" = "<none>"
 "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
-"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83"
+"checksum cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a0c56216487bb80eec9c4516337b2588a4f2a2290d72a1416d930e4dcdb0c90d"
 "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
 "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"
@@ -1126,7 +1095,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
 "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
 "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
-"checksum csv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f0782c7154d8dd08f4adeb5aa22ab178c10281915f7da68d10bb646f03aaee73"
+"checksum csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9044e25afb0924b5a5fc5511689b0918629e85d68ea591e5e87fbf1e85ea1b3b"
 "checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65"
 "checksum decimal 2.0.4 (git+https://github.com/alkis/decimal.git)" = "<none>"
 "checksum derive_utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58ced0880a3b675d62c255bbac6eefd4b4e672954084354cf65960ddea8be6d7"
@@ -1140,41 +1109,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
 "checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da"
 "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
-"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
+"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
 "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
 "checksum lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c106ed999697325a540c43d66a8d5175668cd96d7eb0bdba03a3bd98256cd698"
 "checksum lexical-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e82e023e062f1d25f807ad182008fba1b46538e999f908a08cc0c29e084462e"
-"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917"
+"checksum libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)" = "c6785aa7dd976f5fbf3b71cfd9cd49d7f783c1ff565a858d71031c6c313aa5c6"
 "checksum liner 0.4.5 (git+https://gitlab.redox-os.org/redox-os/liner)" = "<none>"
 "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
 "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
 "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
 "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
-"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
-"checksum num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1"
-"checksum num-complex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656"
+"checksum num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db"
+"checksum num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "57450397855d951f1a41305e54851b1a7b8f5d2e349543a02a2effe25459f718"
+"checksum num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "107b9be86cd2481930688277b675b0114578227f034674726605b8a482d8baf8"
 "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
 "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
-"checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e"
+"checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10"
 "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
 "checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
 "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
 "checksum object-pool 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "656d9629602722ed1e911c3654ca2f60869e828cd5be441ff8383c2341eac4bc"
-"checksum ord_subset 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d7ce14664caf5b27f5656ff727defd68ae1eb75ef3c4d95259361df1eb376bef"
 "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
 "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
 "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
 "checksum permutate 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53b7d5b19a715ffab38693a9dd44b067fdfa2b18eef65bd93562dfe507022fae"
-"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
+"checksum proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)" = "64c827cea7a7ab30ce4593e5e04d7a11617ad6ece2fa230605a78b00ff965316"
 "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
-"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
 "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
 "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
 "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_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
 "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
-"checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832"
+"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
 "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
 "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
 "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
@@ -1184,12 +1151,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
 "checksum redox_syscall 0.1.54 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "<none>"
 "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
-"checksum regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "559008764a17de49a3146b234641644ed37d118d1ef641a0bb573d146edc6ce0"
+"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58"
 "checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
-"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
-"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
+"checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288"
 "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
-"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
+"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f"
 "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
 "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
 "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
@@ -1205,9 +1171,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum stackvector 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c049c77bf85fbc036484c97b008276d539d9ebff9dfbde37b632ebcd5b8746b6"
 "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.15.30 (registry+https://github.com/rust-lang/crates.io-index)" = "66c8865bf5a7cbb662d8b011950060b3c8743dca141b054bf7195b20d314d8e2"
+"checksum syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)" = "ec52cd796e5f01d0067225a5392e70084acc4c0013fa71d55166d38a8b307836"
 "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
-"checksum termion 1.5.1 (git+https://gitlab.redox-os.org/redox-os/termion)" = "<none>"
+"checksum termion 1.5.2 (git+https://gitlab.redox-os.org/redox-os/termion)" = "<none>"
 "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
 "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
 "checksum tinytemplate 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7655088894274afb52b807bd3c87072daa1fedd155068b8705cabfd628956115"
diff --git a/manual/src/builtins.md b/manual/src/builtins.md
index 2db93292d23b9a63e9749ed1e5bdecb8158e2a79..e6df63f5b0150210484e3644c79cc9de7e3661bb 100644
--- a/manual/src/builtins.md
+++ b/manual/src/builtins.md
@@ -141,7 +141,7 @@ exists [-a ARRAY] [-b BINARY] [-d PATH] [--fn FUNCTION] [[-s] STRING]
 
 Performs tests on files and text
 
-## exec 
+## exec
 
 ```
 exec [-ch] [--help] [command [arguments ...]]
@@ -293,7 +293,7 @@ Read some variables
 ## set
 
 ```
-set [ --help ] [-e | +e] [-x | +x] [-o [vi | emacs]] [- | --] [STRING]...
+set [ --help ] [-e | +e] [- | --] [STRING]...
 ```
 
 Set or unset values of shell options and positional parameters.
@@ -304,11 +304,6 @@ and unset using the '+' character.
 
 - **e**: Exit immediately if a command exits with a non-zero status.
 
-- **-o**: Specifies that an argument will follow that sets the key map.
-    - The keymap argument may be either **vi** or **emacs**.
-
-- **-x**: Specifies that commands will be printed as they are executed.
-
 - **--**: Following arguments will be set as positional arguments in the shell.
     - If no argument are supplied, arguments will be unset.
 
@@ -349,32 +344,32 @@ Performs tests on files and text
 
 #### Options
 
-- **-n STRING**:         the length of STRING is nonzero  
-- **STRING**:            equivalent to -n STRING  
-- **-z STRING**:         the length of STRING is zero  
-- **STRING = STRING**:   the strings are equivalent  
-- **STRING != STRING**:  the strings are not equal  
-- **INTEGER -eq INTEGER**: the integers are equal  
-- **INTEGER -ge INTEGER**: the first INTEGER is greater than or equal to the first INTEGER  
-- **INTEGER -gt INTEGER**: the first INTEGER is greater than the first INTEGER  
-- **INTEGER -le INTEGER**: the first INTEGER is less than or equal to the first INTEGER  
-- **INTEGER -lt INTEGER**: the first INTEGER is less than the first INTEGER  
-- **INTEGER -ne INTEGER**: the first INTEGER is not equal to the first INTEGER  
-- **FILE -ef FILE**:     both files have the same device and inode numbers  
-- **FILE -nt FILE**:     the first FILE is newer than the second FILE  
-- **FILE -ot FILE**:     the first file is older than the second FILE  
-- **-b FILE**:          FILE exists and is a block device  
-- **-c FILE**:           FILE exists and is a character device  
-- **-d FILE**:           FILE exists and is a directory  
-- **-e FILE**:           FILE exists  
-- **-f FILE**:           FILE exists and is a regular file  
-- **-h FILE**:           FILE exists and is a symbolic link (same as -L)  
-- **-L FILE**:           FILE exists and is a symbolic link (same as -h)  
-- **-r FILE**:           FILE exists and read permission is granted  
-- **-s FILE**:           FILE exists and has a file size greater than zero  
-- **-S FILE**:           FILE exists and is a socket  
-- **-w FILE**:           FILE exists and write permission is granted  
-- **-x FILE**:           FILE exists and execute (or search) permission is granted  
+- **-n STRING**:         the length of STRING is nonzero
+- **STRING**:            equivalent to -n STRING
+- **-z STRING**:         the length of STRING is zero
+- **STRING = STRING**:   the strings are equivalent
+- **STRING != STRING**:  the strings are not equal
+- **INTEGER -eq INTEGER**: the integers are equal
+- **INTEGER -ge INTEGER**: the first INTEGER is greater than or equal to the first INTEGER
+- **INTEGER -gt INTEGER**: the first INTEGER is greater than the first INTEGER
+- **INTEGER -le INTEGER**: the first INTEGER is less than or equal to the first INTEGER
+- **INTEGER -lt INTEGER**: the first INTEGER is less than the first INTEGER
+- **INTEGER -ne INTEGER**: the first INTEGER is not equal to the first INTEGER
+- **FILE -ef FILE**:     both files have the same device and inode numbers
+- **FILE -nt FILE**:     the first FILE is newer than the second FILE
+- **FILE -ot FILE**:     the first file is older than the second FILE
+- **-b FILE**:          FILE exists and is a block device
+- **-c FILE**:           FILE exists and is a character device
+- **-d FILE**:           FILE exists and is a directory
+- **-e FILE**:           FILE exists
+- **-f FILE**:           FILE exists and is a regular file
+- **-h FILE**:           FILE exists and is a symbolic link (same as -L)
+- **-L FILE**:           FILE exists and is a symbolic link (same as -h)
+- **-r FILE**:           FILE exists and read permission is granted
+- **-s FILE**:           FILE exists and has a file size greater than zero
+- **-S FILE**:           FILE exists and is a socket
+- **-w FILE**:           FILE exists and write permission is granted
+- **-x FILE**:           FILE exists and execute (or search) permission is granted
 
 ## true
 
@@ -447,4 +442,4 @@ isatty [FD]
 Returns 0 exit status if the supplied file descriptor is a tty.
 
 ### Options
-- **not**: returns 0 if the two arguments are not equal.
\ No newline at end of file
+- **not**: returns 0 if the two arguments are not equal.
diff --git a/src/lib/builtins/command_info.rs b/src/lib/builtins/command_info.rs
index e5237d47c10bc3e07d161e94990b4fb531506b49..4de3b5f1f3c835644f4e5b4af268b742bf6bd98a 100644
--- a/src/lib/builtins/command_info.rs
+++ b/src/lib/builtins/command_info.rs
@@ -71,7 +71,7 @@ pub(crate) fn get_command_info<'a>(command: &str, shell: &mut Shell) -> Result<C
         return Ok("alias".into());
     } else if shell.variables.get::<Function>(command).is_some() {
         return Ok("function".into());
-    } else if shell.builtins.contains_key(command) {
+    } else if shell.builtins().contains_key(command) {
         return Ok("builtin".into());
     } else {
         for path in
diff --git a/src/lib/builtins/mod.rs b/src/lib/builtins/mod.rs
index 5844aa8da59c323899da7538a5e5639d98fdc7ad..34609818bce6f1e45455a2b6a405bcd41cac1c94 100644
--- a/src/lib/builtins/mod.rs
+++ b/src/lib/builtins/mod.rs
@@ -1,4 +1,5 @@
 pub mod functions;
+pub mod man_pages;
 pub mod source;
 pub mod variables;
 
@@ -7,7 +8,6 @@ mod exec;
 mod exists;
 mod is;
 mod job_control;
-mod man_pages;
 mod set;
 mod status;
 
@@ -40,7 +40,7 @@ use crate::{
         fork_function::fork_function,
         job_control::{JobControl, ProcessState},
         status::*,
-        Shell, ShellHistory,
+        Shell,
     },
     sys, types,
 };
@@ -55,7 +55,7 @@ const DISOWN_DESC: &str =
     "Disowning a process removes that process from the shell's background process table.";
 
 /// The type for builtin functions. Builtins have direct access to the shell
-pub type BuiltinFunction<'a> = &'a Fn(&[small::String], &mut Shell) -> i32;
+pub type BuiltinFunction<'a> = &'a dyn Fn(&[small::String], &mut Shell) -> i32;
 
 macro_rules! map {
     ($($name:expr => $func:ident: $help:expr),+) => {{
@@ -105,7 +105,6 @@ impl<'a> Default for BuiltinMap<'a> {
             "fg" => builtin_fg : "Resumes and sets a background process as the active process",
             "fn" => builtin_fn : "Print list of functions",
             "help" => builtin_help : HELP_DESC,
-            "history" => builtin_history : "Display a log of all commands previously executed",
             "is" => builtin_is : "Simple alternative to == and !=",
             "isatty" => builtin_isatty : "Returns 0 exit status if the supplied FD is a tty",
             "jobs" => builtin_jobs : "Displays all jobs that are attached to the background",
@@ -130,15 +129,26 @@ impl<'a> Default for BuiltinMap<'a> {
 }
 
 impl<'a> BuiltinMap<'a> {
+    #[inline]
     pub fn new() -> Self { BuiltinMap { fcts: HashMap::new(), help: HashMap::new() } }
 
+    #[inline]
     pub fn contains_key(&self, func: &str) -> bool { self.fcts.get(&func).is_some() }
 
+    #[inline]
     pub fn keys(&self) -> impl Iterator<Item = &str> { self.fcts.keys().cloned() }
 
+    #[inline]
     pub fn get_help(&self, func: &str) -> Option<&str> { self.help.get(func).cloned() }
 
+    #[inline]
     pub fn get(&self, func: &str) -> Option<BuiltinFunction<'a>> { self.fcts.get(func).cloned() }
+
+    #[inline]
+    pub fn add(&mut self, name: &'static str, func: BuiltinFunction<'a>, help: &'static str) {
+        self.fcts.insert(name, func);
+        self.help.insert(name, help);
+    }
 }
 
 fn starts_with(args: &[small::String], _: &mut Shell) -> i32 { conditionals::starts_with(args) }
@@ -322,13 +332,6 @@ fn builtin_eval(args: &[small::String], shell: &mut Shell) -> i32 {
     }
 }
 
-fn builtin_history(args: &[small::String], shell: &mut Shell) -> i32 {
-    if check_help(args, MAN_HISTORY) {
-        return SUCCESS;
-    }
-    shell.print_history(args)
-}
-
 fn builtin_source(args: &[small::String], shell: &mut Shell) -> i32 {
     if check_help(args, MAN_SOURCE) {
         return SUCCESS;
@@ -459,7 +462,7 @@ fn builtin_disown(args: &[small::String], shell: &mut Shell) -> i32 {
 }
 
 fn builtin_help(args: &[small::String], shell: &mut Shell) -> i32 {
-    let builtins = &shell.builtins;
+    let builtins = shell.builtins();
     let stdout = io::stdout();
     let mut stdout = stdout.lock();
     if let Some(command) = args.get(1) {
diff --git a/src/lib/builtins/set.rs b/src/lib/builtins/set.rs
index 36faf6aace8b524046dcec875c53122bfab4d3d1..732a2fbee4595247271f39d7f8c78319345f13a8 100644
--- a/src/lib/builtins/set.rs
+++ b/src/lib/builtins/set.rs
@@ -2,7 +2,6 @@ use crate::{
     shell::{flags::*, Shell},
     types,
 };
-use liner::KeyBindings;
 use small;
 use std::iter;
 
@@ -32,28 +31,6 @@ pub(crate) fn set(args: &[small::String], shell: &mut Shell) -> i32 {
             for flag in arg.bytes().skip(1) {
                 match flag {
                     b'e' => shell.flags |= ERR_EXIT,
-                    b'o' => match args_iter.next().map(|s| s as &str) {
-                        Some("vi") => {
-                            if let Some(context) = shell.context.as_mut() {
-                                context.key_bindings = KeyBindings::Vi;
-                            }
-                        }
-                        Some("emacs") => {
-                            if let Some(context) = shell.context.as_mut() {
-                                context.key_bindings = KeyBindings::Emacs;
-                            }
-                        }
-                        Some("huponexit") => shell.flags |= HUPONEXIT,
-                        Some(_) => {
-                            eprintln!("ion: set: invalid option");
-                            return 0;
-                        }
-                        None => {
-                            eprintln!("ion: set: no option given");
-                            return 0;
-                        }
-                    },
-                    b'x' => shell.flags |= PRINT_COMMS,
                     _ => return 0,
                 }
             }
diff --git a/src/lib/builtins/status.rs b/src/lib/builtins/status.rs
index 74b30d5aec4173b3e72a4f544d5450a2eae168c5..0aeee25e52c02bf02dd81c6c6e62478d53082c39 100644
--- a/src/lib/builtins/status.rs
+++ b/src/lib/builtins/status.rs
@@ -8,64 +8,62 @@ pub(crate) fn status(args: &[small::String], shell: &mut Shell) -> Result<(), St
     let mut interactive = false;
     let mut filename = false;
 
-    let shell_args: Vec<_> = env::args().collect();
+    let is_login = env::args().nth(0).unwrap().chars().nth(0).unwrap() == '-';
 
-    let is_login = shell_args[0].chars().nth(0).unwrap() == '-';
-
-    let args_len = args.len();
-    if args_len == 1 {
-        if is_login {
-            println!("This is a login shell");
-        } else {
-            println!("This is not a login shell");
-        }
-    } else if args_len > 2 {
-        return Err("status takes one argument\n".to_string());
-    } else {
-        for arg in args {
-            match &**arg {
-                "--help" => help = true,
-                "--is-login" => login_shell = true,
-                "--is-interactive" => interactive = true,
-                "--current-filename" => filename = true,
-                _ => {
-                    if arg.starts_with('-') {
-                        match arg.chars().nth(1).unwrap() {
-                            'h' => help = true,
-                            'l' => login_shell = true,
-                            'i' => interactive = true,
-                            'f' => filename = true,
-                            _ => (),
+    match args.len() {
+        0 => {
+            for arg in args {
+                match &**arg {
+                    "--help" => help = true,
+                    "--is-login" => login_shell = true,
+                    "--is-interactive" => interactive = true,
+                    "--current-filename" => filename = true,
+                    _ => {
+                        if arg.starts_with('-') {
+                            match arg.chars().nth(1).unwrap() {
+                                'h' => help = true,
+                                'l' => login_shell = true,
+                                'i' => interactive = true,
+                                'f' => filename = true,
+                                _ => (),
+                            }
                         }
                     }
                 }
             }
-        }
 
-        if login_shell && !is_login {
-            return Err("".to_string());
-        }
+            if login_shell && !is_login {
+                return Err("".to_string());
+            }
 
-        if interactive && shell.is_background_shell || shell.is_library {
-            return Err("".to_string());
-        }
+            if interactive && shell.is_background_shell || shell.is_library {
+                return Err("".to_string());
+            }
 
-        if filename {
-            // TODO: This will not work if ion is renamed.
-            let sa_len = shell_args.len() - 1;
-            let last_sa = &shell_args[sa_len];
-            let last_3: String = last_sa[last_sa.len() - 3..last_sa.len()].to_string();
+            if filename {
+                // TODO: This will not work if ion is renamed.
+                let last_sa = &env::args().last().unwrap();
+                let last_3: String = last_sa[last_sa.len() - 3..last_sa.len()].to_string();
+                if last_3 == "ion" {
+                    println!("stdio");
+                } else {
+                    println!("{}", last_sa);
+                }
+            }
 
-            if last_3 == "ion" {
-                println!("stdio");
-            } else {
-                println!("{}", last_sa);
+            if help {
+                println!("{}", MAN_STATUS);
             }
+            Ok(())
         }
-
-        if help {
-            println!("{}", MAN_STATUS);
+        1 => {
+            if is_login {
+                println!("This is a login shell");
+            } else {
+                println!("This is not a login shell");
+            }
+            Ok(())
         }
+        _ => Err("status takes one argument\n".to_string()),
     }
-    Ok(())
 }
diff --git a/src/lib/lib.rs b/src/lib/lib.rs
index 654a27501da40d307617df12ee27edb3cbce4154..0091e3ce1d720d7e5c81797f347ca389fce2a692 100644
--- a/src/lib/lib.rs
+++ b/src/lib/lib.rs
@@ -18,8 +18,8 @@ pub mod shell;
 
 pub(crate) use self::memory::IonPool;
 pub use crate::shell::{
-    binary::MAN_ION, flags, pipe_exec::job_control::JobControl, status, Binary, Capture, Fork,
-    IonError, IonResult, Shell, ShellBuilder,
+    binary::MAN_ION, flags, pipe_exec::job_control::JobControl, status, Capture, Fork,
+    InteractiveBinary, IonError, IonResult, Shell, ShellBuilder,
 };
 
 pub fn version() -> &'static str { include!(concat!(env!("OUT_DIR"), "/version_string")) }
diff --git a/src/lib/shell/assignments.rs b/src/lib/shell/assignments.rs
index 53320be6adf9b62644f9d4b9a0a4f6673de1b0a4..caed8186baacc627055c2da93380f96f9cb2c8b1 100644
--- a/src/lib/shell/assignments.rs
+++ b/src/lib/shell/assignments.rs
@@ -6,10 +6,7 @@ use super::{
 use crate::{
     lexers::assignments::{Key, Operator, Primitive},
     parser::{assignments::*, statement::parse::is_valid_name},
-    shell::{
-        history::ShellHistory,
-        variables::{EuclDiv, Modifications, OpError, Pow, Value},
-    },
+    shell::variables::{EuclDiv, Modifications, OpError, Pow, Value},
     types,
 };
 use std::{
@@ -142,15 +139,6 @@ impl<'b> VariableStore<'b> for Shell<'b> {
             let rhs = value_check(self, &expression, &key.kind)
                 .map_err(|why| format!("{}: {}", key.name, why))?;
 
-            // When we changed the HISTORY_IGNORE variable, update the
-            // ignore patterns. This happens first because `set_array`
-            // consumes 'values'
-            if key.name == "HISTORY_IGNORE" {
-                if let Value::Array(array) = &rhs {
-                    self.update_ignore_patterns(array);
-                }
-            }
-
             match (&rhs, &key.kind) {
                 (Value::HashMap(_), Primitive::Indexed(..)) => {
                     Err("cannot insert hmap into index".to_string())?
diff --git a/src/lib/shell/binary/designators.rs b/src/lib/shell/binary/designators.rs
index aff6ebd5bf237996fe803a3326e0a1883dc9859a..2f837ef264cb4d3221149a7d062dd7f3217f2109 100644
--- a/src/lib/shell/binary/designators.rs
+++ b/src/lib/shell/binary/designators.rs
@@ -1,33 +1,29 @@
-use crate::{
-    lexers::{ArgumentSplitter, DesignatorLexer, DesignatorToken},
-    shell::Shell,
-};
+use crate::lexers::{ArgumentSplitter, DesignatorLexer, DesignatorToken};
+use liner::Context;
 use std::{borrow::Cow, str};
 
-pub(crate) fn expand_designators<'a>(shell: &Shell, cmd: &'a str) -> Cow<'a, str> {
-    if let Some(ref context) = shell.context {
-        if let Some(buffer) = context.history.buffers.back() {
-            let buffer = buffer.as_bytes();
-            let buffer = unsafe { str::from_utf8_unchecked(&buffer) };
-            let mut output = String::with_capacity(cmd.len());
-            for token in DesignatorLexer::new(cmd.as_bytes()) {
-                match token {
-                    DesignatorToken::Text(text) => output.push_str(text),
-                    DesignatorToken::Designator(text) => match text {
-                        "!!" => output.push_str(buffer),
-                        "!$" => output.push_str(last_arg(buffer)),
-                        "!0" => output.push_str(command(buffer)),
-                        "!^" => output.push_str(first_arg(buffer)),
-                        "!*" => output.push_str(&args(buffer)),
-                        _ => output.push_str(text),
-                    },
-                }
+pub(crate) fn expand_designators<'a>(context: &Context, cmd: &'a str) -> Cow<'a, str> {
+    if let Some(buffer) = context.history.buffers.back() {
+        let buffer = buffer.as_bytes();
+        let buffer = unsafe { str::from_utf8_unchecked(&buffer) };
+        let mut output = String::with_capacity(cmd.len());
+        for token in DesignatorLexer::new(cmd.as_bytes()) {
+            match token {
+                DesignatorToken::Text(text) => output.push_str(text),
+                DesignatorToken::Designator(text) => match text {
+                    "!!" => output.push_str(buffer),
+                    "!$" => output.push_str(last_arg(buffer)),
+                    "!0" => output.push_str(command(buffer)),
+                    "!^" => output.push_str(first_arg(buffer)),
+                    "!*" => output.push_str(&args(buffer)),
+                    _ => output.push_str(text),
+                },
             }
-            return Cow::Owned(output);
         }
+        Cow::Owned(output)
+    } else {
+        Cow::Borrowed(cmd)
     }
-
-    Cow::Borrowed(cmd)
 }
 
 fn command(text: &str) -> &str { ArgumentSplitter::new(text).next().unwrap_or(text) }
diff --git a/src/lib/shell/history.rs b/src/lib/shell/binary/history.rs
similarity index 67%
rename from src/lib/shell/history.rs
rename to src/lib/shell/binary/history.rs
index 07ffb26f8f1ed2f9e8e9f91ee9a9aa46cb4ec805..74b15d0c9ae1f1fb2e6a08bac4d49c1f83aa0789 100644
--- a/src/lib/shell/history.rs
+++ b/src/lib/shell/binary/history.rs
@@ -1,12 +1,8 @@
-use crate::shell::{status::*, Shell};
+use super::InteractiveBinary;
+use crate::{shell::status::*, types};
 
-use crate::types;
 use regex::Regex;
-use small;
-use std::{
-    io::{self, Write},
-    time::{SystemTime, UNIX_EPOCH},
-};
+use std::time::{SystemTime, UNIX_EPOCH};
 
 #[derive(Debug, Default)]
 pub(crate) struct IgnoreSetting {
@@ -27,27 +23,24 @@ pub(crate) struct IgnoreSetting {
 
 /// Contains all history-related functionality for the `Shell`.
 pub(crate) trait ShellHistory {
-    /// Prints the commands contained within the history buffers to standard
-    /// output.
-    fn print_history(&self, _arguments: &[small::String]) -> i32;
-
     /// Saves a command in the history, depending on @HISTORY_IGNORE. Should be called
     /// immediately after `on_command()`
-    fn save_command_in_history(&mut self, command: &str);
+    fn save_command_in_history(&self, command: &str);
 
     /// Updates the history ignore patterns. Call this whenever HISTORY_IGNORE
     /// is changed.
-    fn update_ignore_patterns(&mut self, patterns: &types::Array);
+    fn ignore_patterns(&self) -> IgnoreSetting;
 }
 
 trait ShellHistoryPrivate {
     /// Returns true if the given command with the given exit status should be saved in the
     /// history
-    fn should_save_command(&mut self, command: &str) -> bool;
+    fn should_save_command(&self, command: &str) -> bool;
 }
 
-impl<'a> ShellHistory for Shell<'a> {
-    fn update_ignore_patterns(&mut self, patterns: &types::Array) {
+impl<'a> ShellHistory for InteractiveBinary<'a> {
+    fn ignore_patterns(&self) -> IgnoreSetting {
+        let patterns: types::Array = self.shell.borrow().variables.get("HISTORY_IGNORE").unwrap();
         let mut settings = IgnoreSetting::default();
         let mut regexes = Vec::new();
         // for convenience and to avoid typos
@@ -72,50 +65,35 @@ impl<'a> ShellHistory for Shell<'a> {
         }
         settings.regexes = if !regexes.is_empty() { Some(regexes) } else { None };
 
-        self.ignore_setting = settings;
+        settings
     }
 
-    fn save_command_in_history(&mut self, command: &str) {
+    fn save_command_in_history(&self, command: &str) {
         if self.should_save_command(command) {
-            if self.variables.get_str_or_empty("HISTORY_TIMESTAMP") == "1" {
+            if self.shell.borrow().variables.get_str_or_empty("HISTORY_TIMESTAMP") == "1" {
                 // Get current time stamp
                 let since_unix_epoch =
                     SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
                 let cur_time_sys = ["#", &since_unix_epoch.to_owned().to_string()].concat();
 
                 // Push current time to history
-                if let Err(err) = self.context.as_mut().unwrap().history.push(cur_time_sys.into()) {
+                if let Err(err) = self.context.borrow_mut().history.push(cur_time_sys.into()) {
                     eprintln!("ion: {}", err)
                 }
             }
 
             // Push command itself to history
-            if let Err(err) = self.context.as_mut().unwrap().history.push(command.into()) {
+            if let Err(err) = self.context.borrow_mut().history.push(command.into()) {
                 eprintln!("ion: {}", err);
             }
         }
     }
-
-    fn print_history(&self, _arguments: &[small::String]) -> i32 {
-        if let Some(context) = self.context.as_ref() {
-            let mut buffer = Vec::with_capacity(8 * 1024);
-            for command in &context.history {
-                let _ = writeln!(buffer, "{}", command);
-            }
-            let stdout = io::stdout();
-            let mut stdout = stdout.lock();
-            let _ = stdout.write_all(&buffer);
-            SUCCESS
-        } else {
-            FAILURE
-        }
-    }
 }
 
-impl<'a> ShellHistoryPrivate for Shell<'a> {
-    fn should_save_command(&mut self, command: &str) -> bool {
+impl<'a> ShellHistoryPrivate for InteractiveBinary<'a> {
+    fn should_save_command(&self, command: &str) -> bool {
         // just for convenience and to make the code look a bit cleaner
-        let ignore = &self.ignore_setting;
+        let ignore = self.ignore_patterns();
 
         // without the second check the command which sets the local variable would
         // also be ignored. However, this behavior might not be wanted.
@@ -129,20 +107,15 @@ impl<'a> ShellHistoryPrivate for Shell<'a> {
             return false;
         }
 
-        if ignore.no_such_command && self.previous_status == NO_SUCH_COMMAND {
+        if ignore.no_such_command && self.shell.borrow().previous_status == NO_SUCH_COMMAND {
             return false;
         }
 
         if ignore.duplicates {
-            if let Some(ref mut context) = self.context {
-                context.history.remove_duplicates(command);
-                return true;
-            } else {
-                return false;
-            }
+            self.context.borrow_mut().history.remove_duplicates(command);
         }
 
-        if let Some(ref regexes) = self.ignore_setting.regexes.as_ref() {
+        if let Some(ref regexes) = ignore.regexes {
             // ignore command when regex is matched but only if it does not contain
             // "HISTORY_IGNORE", otherwise we would also ignore the command which
             // sets the variable, which could be annoying.
diff --git a/src/lib/shell/binary/mod.rs b/src/lib/shell/binary/mod.rs
index 7a0b15f156570a62bfa16a687ca8dbda2408b380..079ea7d44b6b1a9e1c1de4d07bd1738e12085b49 100644
--- a/src/lib/shell/binary/mod.rs
+++ b/src/lib/shell/binary/mod.rs
@@ -1,19 +1,24 @@
 //! Contains the binary logic of Ion.
 mod designators;
+mod history;
 mod prompt;
 mod readln;
 
-use self::{
-    prompt::{prompt, prompt_fn},
-    readln::readln,
+use self::{history::ShellHistory, prompt::prompt, readln::readln};
+use super::{
+    flags::{HUPONEXIT, UNTERMINATED},
+    pipe_exec::job_control::JobControl,
+    status::SUCCESS,
+    FlowLogic, Shell,
 };
-use super::{flags::UNTERMINATED, status::*, FlowLogic, Shell, ShellHistory};
 use crate::{
+    builtins::man_pages,
     parser::{shell_expand::Expander, Terminator},
     types,
 };
-use liner::{Buffer, Context};
-use std::path::Path;
+use itertools::Itertools;
+use liner::{Buffer, Context, KeyBindings};
+use std::{cell::RefCell, path::Path, rc::Rc};
 
 pub const MAN_ION: &str = "NAME
     Ion - The Ion shell
@@ -38,84 +43,129 @@ ARGS:
     <args>...    Script arguments (@args). If the -c option is not specified, the first
                  parameter is taken as a filename to execute";
 
-pub trait Binary {
-    /// Parses and executes the arguments that were supplied to the shell.
-    fn execute_script<T: std::io::Read>(&mut self, lines: T);
-    /// Creates an interactive session that reads from a prompt provided by
-    /// Liner.
-    fn execute_interactive(self);
-    /// Ion's interface to Liner's `read_line` method, which handles everything related to
-    /// rendering, controlling, and getting input from the prompt.
-    fn readln(&mut self) -> Option<String>;
-    /// Generates the prompt that will be used by Liner.
-    fn prompt(&mut self) -> String;
-    // Executes the PROMPT function, if it exists, and returns the output.
-    fn prompt_fn(&mut self) -> Option<String>;
-    // Handles commands given by the REPL, and saves them to history.
-    fn save_command(&mut self, command: &str);
+pub struct InteractiveBinary<'a> {
+    context: Rc<RefCell<Context>>,
+    shell:   RefCell<Shell<'a>>,
 }
 
-impl<'a> Binary for Shell<'a> {
-    fn save_command(&mut self, cmd: &str) {
-        if !cmd.ends_with('/') && self.tilde(cmd).map_or(false, |path| Path::new(&path).is_dir()) {
+impl<'a> InteractiveBinary<'a> {
+    pub fn new(shell: Shell<'a>) -> Self {
+        let mut context = Context::new();
+        context.word_divider_fn = Box::new(word_divide);
+        if shell.get_str_or_empty("HISTFILE_ENABLED") == "1" {
+            let path = shell.get::<types::Str>("HISTFILE").expect("shell didn't set HISTFILE");
+            if !Path::new(path.as_str()).exists() {
+                eprintln!("ion: creating history file at \"{}\"", path);
+            }
+            let _ = context.history.set_file_name_and_load_history(path.as_str());
+        }
+        InteractiveBinary { context: Rc::new(RefCell::new(context)), shell: RefCell::new(shell) }
+    }
+
+    /// Handles commands given by the REPL, and saves them to history.
+    pub fn save_command(&self, cmd: &str) {
+        if !cmd.ends_with('/')
+            && self.shell.borrow().tilde(cmd).map_or(false, |path| Path::new(&path).is_dir())
+        {
             self.save_command_in_history(&[cmd, "/"].concat());
         } else {
             self.save_command_in_history(cmd);
         }
     }
 
-    fn execute_interactive(mut self) {
-        self.context = Some({
-            let mut context = Context::new();
-            context.word_divider_fn = Box::new(word_divide);
-            if "1" == self.get_str_or_empty("HISTFILE_ENABLED") {
-                let path = self.get::<types::Str>("HISTFILE").expect("shell didn't set HISTFILE");
-                if !Path::new(path.as_str()).exists() {
-                    eprintln!("ion: creating history file at \"{}\"", path);
-                }
-                let _ = context.history.set_file_name_and_load_history(path.as_str());
+    #[inline]
+    pub fn init_file(&self) { self.shell.borrow_mut().evaluate_init_file(); }
+
+    pub fn add_callbacks(&self) {
+        let mut shell = self.shell.borrow_mut();
+        let context = self.context.clone();
+        shell.set_prep_for_exit(Some(Box::new(move |shell| {
+            // context will be sent a signal to commit all changes to the history file,
+            // and waiting for the history thread in the background to finish.
+            if shell.flags & HUPONEXIT != 0 {
+                shell.resume_stopped();
+                shell.background_send(sys::SIGHUP);
             }
-            context
-        });
+            context.borrow_mut().history.commit_to_file();
+        })));
+
+        let context = self.context.clone();
+        shell.set_on_command(Some(Box::new(move |shell, elapsed| {
+            // If `RECORD_SUMMARY` is set to "1" (True, Yes), then write a summary of the
+            // pipline just executed to the the file and context histories. At the
+            // moment, this means record how long it took.
+            if "1" == shell.variables.get_str_or_empty("RECORD_SUMMARY") {
+                let summary = format!(
+                    "#summary# elapsed real time: {}.{:09} seconds",
+                    elapsed.as_secs(),
+                    elapsed.subsec_nanos()
+                );
+                println!("{:?}", summary);
+                context.borrow_mut().history.push(summary.into()).unwrap_or_else(|err| {
+                    eprintln!("ion: history append: {}", err);
+                });
+            }
+        })));
+    }
 
-        self.evaluate_init_file();
+    /// Creates an interactive session that reads from a prompt provided by
+    /// Liner.
+    pub fn execute_interactive(self) -> ! {
+        let context_bis = self.context.clone();
+        let history = &move |args: &[small::String], _shell: &mut Shell| -> i32 {
+            if man_pages::check_help(args, man_pages::MAN_HISTORY) {
+                return SUCCESS;
+            }
+
+            print!("{}", context_bis.borrow().history.buffers.iter().format("\n"));
+            SUCCESS
+        };
+
+        // change the lifetime to allow adding local builtins
+        let InteractiveBinary { context, shell } = self;
+        let this = InteractiveBinary { context, shell: RefCell::new(shell.into_inner()) };
+
+        this.shell.borrow_mut().builtins_mut().add(
+            "history",
+            history,
+            "Display a log of all commands previously executed",
+        );
 
         loop {
-            let mut lines = std::iter::repeat_with(|| self.readln())
+            let mut lines = std::iter::repeat_with(|| this.readln())
                 .filter_map(|cmd| cmd)
                 .flat_map(|s| s.into_bytes().into_iter().chain(Some(b'\n')));
             match Terminator::new(&mut lines).terminate() {
                 Some(command) => {
-                    self.flags &= !UNTERMINATED;
-                    let cmd: &str = &designators::expand_designators(&self, command.trim_end());
-                    self.on_command(&cmd);
-                    self.save_command(&cmd);
+                    this.shell.borrow_mut().flags &= !UNTERMINATED;
+                    let cmd: &str = &designators::expand_designators(
+                        &this.context.borrow(),
+                        command.trim_end(),
+                    );
+                    this.shell.borrow_mut().on_command(&cmd);
+                    this.save_command(&cmd);
                 }
                 None => {
-                    self.flags &= !UNTERMINATED;
+                    this.shell.borrow_mut().flags &= !UNTERMINATED;
                 }
             }
         }
     }
 
-    fn execute_script<T: std::io::Read>(&mut self, lines: T) {
-        if self.execute_command(lines).is_err() {
-            eprintln!("ion: unterminated quote in script");
-            self.previous_status = FAILURE;
-        } else if self.flow_control.unclosed_block() {
-            eprintln!(
-                "ion: unexpected end of script: expected end block for `{}`",
-                self.flow_control.block.last().unwrap().short(),
-            );
-            self.previous_status = FAILURE;
-        }
+    /// Set the keybindings of the underlying liner context
+    #[inline]
+    pub fn set_keybindings(&mut self, key_bindings: KeyBindings) {
+        self.context.borrow_mut().key_bindings = key_bindings;
     }
 
-    fn readln(&mut self) -> Option<String> { readln(self) }
-
-    fn prompt_fn(&mut self) -> Option<String> { prompt_fn(self) }
+    /// Ion's interface to Liner's `read_line` method, which handles everything related to
+    /// rendering, controlling, and getting input from the prompt.
+    #[inline]
+    pub fn readln(&self) -> Option<String> { readln(self) }
 
-    fn prompt(&mut self) -> String { prompt(self) }
+    /// Generates the prompt that will be used by Liner.
+    #[inline]
+    pub fn prompt(&self) -> String { prompt(&self.shell.borrow_mut()) }
 }
 
 #[derive(Debug)]
diff --git a/src/lib/shell/binary/prompt.rs b/src/lib/shell/binary/prompt.rs
index 8f313183b23249c9d517511adf5d587cbbd82876..dfaa8cc5f8ffa3c37df37ccdd20596f4b6b3e19e 100644
--- a/src/lib/shell/binary/prompt.rs
+++ b/src/lib/shell/binary/prompt.rs
@@ -5,19 +5,19 @@ use crate::{
 };
 use std::{io::Read, process};
 
-pub(crate) fn prompt(shell: &mut Shell) -> String {
+pub(crate) fn prompt(shell: &Shell) -> String {
     let blocks =
         shell.flow_control.block.len() + if shell.flags & UNTERMINATED != 0 { 1 } else { 0 };
 
     if blocks == 0 {
-        prompt_fn(shell)
-            .unwrap_or_else(|| expand_string(&shell.get_str_or_empty("PROMPT"), shell).join(" "))
+        prompt_fn(&shell)
+            .unwrap_or_else(|| expand_string(&shell.get_str_or_empty("PROMPT"), &*shell).join(" "))
     } else {
         "    ".repeat(blocks)
     }
 }
 
-pub(crate) fn prompt_fn(shell: &mut Shell) -> Option<String> {
+pub(crate) fn prompt_fn(shell: &Shell) -> Option<String> {
     if let Some(Value::Function(function)) = shell.variables.get_ref("PROMPT") {
         let output = match shell.fork(Capture::StdoutThenIgnoreStderr, move |child| {
             let _ = function.execute(child, &["ion"]);
diff --git a/src/lib/shell/binary/readln.rs b/src/lib/shell/binary/readln.rs
index 0db3980ed8466d16b3c0bcdc0f83354426422d02..1200a27c5a5c0c39c415a26051a070ce88dadbc5 100644
--- a/src/lib/shell/binary/readln.rs
+++ b/src/lib/shell/binary/readln.rs
@@ -1,19 +1,20 @@
-use super::super::{completer::*, flags, Binary, Shell};
+use super::{
+    super::{completer::*, flags},
+    InteractiveBinary,
+};
 use crate::{sys, types};
 use liner::{BasicCompleter, CursorPosition, Event, EventKind};
 use std::{env, io::ErrorKind, mem, path::PathBuf};
 
-pub(crate) fn readln(shell: &mut Shell) -> Option<String> {
-    let prompt = shell.prompt();
-    let dirs = &shell.directory_stack;
-    let prev = shell.variables.get::<types::Str>("OLDPWD");
-    let builtins = &shell.builtins;
-    let vars = &shell.variables;
+pub(crate) fn readln(binary: &InteractiveBinary) -> Option<String> {
+    let prompt = binary.prompt();
+    let line =
+        binary.context.borrow_mut().read_line(prompt, None, &mut |Event { editor, kind }| {
+            let shell = binary.shell.borrow();
+            let dirs = &shell.directory_stack;
+            let prev = &shell.variables.get::<types::Str>("OLDPWD");
+            let vars = &shell.variables;
 
-    let line = shell.context.as_mut().unwrap().read_line(
-        prompt,
-        None,
-        &mut move |Event { editor, kind }| {
             if let EventKind::BeforeComplete = kind {
                 let (words, pos) = editor.get_words_and_cursor_position();
 
@@ -44,7 +45,8 @@ pub(crate) fn readln(shell: &mut Shell) -> Option<String> {
                     // will be used
                     // in the creation of a custom completer.
                     let custom_completer = BasicCompleter::new(
-                        builtins
+                        shell
+                            .builtins()
                             .keys()
                             // Add built-in commands to the completer's definitions.
                             .map(|s| s.to_string())
@@ -61,7 +63,7 @@ pub(crate) fn readln(shell: &mut Shell) -> Option<String> {
                             // it free to do String->SmallString
                             //       and mostly free to go back (free if allocated)
                             .chain(vars.string_vars().map(|(s, _)| ["$", &s].concat()))
-                            .collect::<Vec<String>>(),
+                            .collect(),
                     );
 
                     // Creates completers containing definitions from all directories
@@ -87,13 +89,12 @@ pub(crate) fn readln(shell: &mut Shell) -> Option<String> {
                     mem::replace(&mut editor.context().completer, Some(Box::new(completer)));
                 }
             }
-        },
-    );
+        });
 
     match line {
         Ok(line) => {
             if line.bytes().next() != Some(b'#') && line.bytes().any(|c| !c.is_ascii_whitespace()) {
-                shell.flags |= flags::UNTERMINATED;
+                binary.shell.borrow_mut().flags |= flags::UNTERMINATED;
             }
             Some(line)
         }
@@ -101,11 +102,11 @@ pub(crate) fn readln(shell: &mut Shell) -> Option<String> {
         Err(ref err) if err.kind() == ErrorKind::Interrupted => None,
         // Handles Ctrl + D
         Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => {
-            if shell.flow_control.unclosed_block() {
-                shell.flow_control.pop();
+            if binary.shell.borrow_mut().flow_control.pop() {
                 None
             } else {
-                shell.exit(shell.previous_status);
+                let status = binary.shell.borrow().previous_status;
+                binary.shell.borrow_mut().exit(status);
             }
         }
         Err(err) => {
diff --git a/src/lib/shell/flow_control.rs b/src/lib/shell/flow_control.rs
index 875f7e938be85fd35e66ae420346dc4f094e82b1..70172f2f8894f5d483e3d0d70c0578055d503d51 100644
--- a/src/lib/shell/flow_control.rs
+++ b/src/lib/shell/flow_control.rs
@@ -159,14 +159,16 @@ impl<'a> FlowControl<'a> {
     pub(crate) fn reset(&mut self) { self.block.clear() }
 
     /// Discard one block.
-    pub(crate) fn pop(&mut self) { self.block.pop(); }
+    pub(crate) fn pop(&mut self) -> bool { self.block.pop().is_some() }
 
     /// Check if there isn't an unfinished block.
-    pub(crate) fn unclosed_block(&self) -> bool { !self.block.is_empty() }
+    pub(crate) fn unclosed_block(&self) -> Option<&str> {
+        self.block.last().map(|block| block.short())
+    }
 }
 
 impl<'a> Default for FlowControl<'a> {
-    fn default() -> FlowControl<'static> { FlowControl { block: Vec::with_capacity(5) } }
+    fn default() -> Self { FlowControl { block: Vec::with_capacity(5) } }
 }
 
 pub(crate) fn insert_statement<'a>(
diff --git a/src/lib/shell/fork.rs b/src/lib/shell/fork.rs
index f25005196f1ee72f33953798336351cb47d75cfb..96e9ee4181853b804c1a4de6062ef78ee346ed85 100644
--- a/src/lib/shell/fork.rs
+++ b/src/lib/shell/fork.rs
@@ -48,7 +48,7 @@ pub enum Capture {
 /// Utilized by the shell for performing forks and capturing streams.
 ///
 /// Using this structure directly is equivalent to using `Shell`'s fork method.
-pub struct Fork<'a, 'b> {
+pub struct Fork<'a, 'b: 'a> {
     shell:   &'a Shell<'b>,
     capture: Capture,
 }
@@ -65,10 +65,13 @@ pub struct IonResult {
     pub status: u8,
 }
 
-impl<'a, 'b: 'a> Fork<'a, 'b> {
+impl<'a, 'b> Fork<'a, 'b> {
     /// Executes a closure within the child of the fork, and returning an `IonResult` in a
     /// non-blocking fashion.
-    pub fn exec<F: FnMut(&mut Shell<'b>)>(&self, mut child_func: F) -> Result<IonResult, IonError> {
+    pub fn exec<F: FnMut(&mut Shell<'b>) + 'a>(
+        self,
+        mut child_func: F,
+    ) -> Result<IonResult, IonError> {
         sys::signals::block();
 
         // If we are to capture stdout, create a pipe for capturing outputs.
@@ -129,7 +132,6 @@ impl<'a, 'b: 'a> Fork<'a, 'b> {
                 // Obtain ownership of the child's copy of the shell, and then configure it.
                 let mut shell: Shell = unsafe { (self.shell as *const Shell).read() };
                 shell.set("PID", sys::getpid().unwrap_or(0).to_string());
-                let _ = shell.context.take();
 
                 // Execute the given closure within the child's shell.
                 child_func(&mut shell);
diff --git a/src/lib/shell/mod.rs b/src/lib/shell/mod.rs
index c07f6a7194e7edd7f43e2fed14a45a70bff06617..23ea6c2cf3c8686cab076a0417a50bd5dc08b98f 100644
--- a/src/lib/shell/mod.rs
+++ b/src/lib/shell/mod.rs
@@ -8,7 +8,6 @@ mod flow;
 pub(crate) mod flow_control;
 mod fork;
 pub mod fork_function;
-mod history;
 mod job;
 pub(crate) mod pipe_exec;
 pub(crate) mod signals;
@@ -29,12 +28,11 @@ pub mod flags {
 }
 
 pub use self::{
-    binary::Binary,
+    binary::InteractiveBinary,
     fork::{Capture, Fork, IonResult},
 };
 pub(crate) use self::{
     flow::FlowLogic,
-    history::{IgnoreSetting, ShellHistory},
     job::{Job, JobKind},
     pipe_exec::{foreground, job_control},
 };
@@ -45,7 +43,7 @@ use self::{
     flags::*,
     flow_control::{FlowControl, Function, FunctionError},
     foreground::ForegroundSignals,
-    job_control::{BackgroundProcess, JobControl},
+    job_control::BackgroundProcess,
     pipe_exec::PipelineExecution,
     status::*,
     variables::{GetVariable, Value, Variables},
@@ -57,7 +55,6 @@ use crate::{
     sys, types,
 };
 use itertools::Itertools;
-use liner::Context;
 use std::{
     fs,
     io::{self, Read, Write},
@@ -80,6 +77,8 @@ pub enum IonError {
     Unterminated,
     #[error(display = "function error: {}", why)]
     Function { why: FunctionError },
+    #[error(display = "unexpected end of script: expected end block for `{}`", block)]
+    UnclosedBlock { block: String },
 }
 
 /// The shell structure is a megastructure that manages all of the state of the shell throughout
@@ -89,10 +88,7 @@ pub enum IonError {
 pub struct Shell<'a> {
     /// Contains a list of built-in commands that were created when the program
     /// started.
-    pub(crate) builtins: BuiltinMap<'a>,
-    /// Contains the history, completions, and manages writes to the history file.
-    /// Note that the context is only available in an interactive session.
-    pub(crate) context: Option<Context>,
+    builtins: BuiltinMap<'a>,
     /// Contains the aliases, strings, and array variable maps.
     pub variables: Variables<'a>,
     /// Contains the current state of flow control parameters.
@@ -119,9 +115,10 @@ pub struct Shell<'a> {
     /// When the `fg` command is run, this will be used to communicate with the specified
     /// background process.
     foreground_signals: Arc<ForegroundSignals>,
-    /// Stores the patterns used to determine whether a command should be saved in the history
-    /// or not
-    ignore_setting: IgnoreSetting,
+    /// Custom callback to cleanup before exit
+    prep_for_exit: Option<Box<FnMut(&mut Shell) + 'a>>,
+    /// Custom callback for each command call
+    on_command: Option<Box<Fn(&Shell, std::time::Duration) + 'a>>,
 }
 
 #[derive(Default)]
@@ -132,7 +129,7 @@ impl ShellBuilder {
 
     pub fn as_library<'a>(&self) -> Shell<'a> { Shell::new(true) }
 
-    pub fn set_unique_pid(self) -> ShellBuilder {
+    pub fn set_unique_pid(self) -> Self {
         if let Ok(pid) = sys::getpid() {
             if sys::setpgid(0, pid).is_ok() {
                 let _ = sys::tcsetpgrp(0, pid);
@@ -142,7 +139,7 @@ impl ShellBuilder {
         self
     }
 
-    pub fn block_signals(self) -> ShellBuilder {
+    pub fn block_signals(self) -> Self {
         // This will block SIGTSTP, SIGTTOU, SIGTTIN, and SIGCHLD, which is required
         // for this shell to manage its own process group / children / etc.
         signals::block();
@@ -150,7 +147,7 @@ impl ShellBuilder {
         self
     }
 
-    pub fn install_signal_handler(self) -> ShellBuilder {
+    pub fn install_signal_handler(self) -> Self {
         extern "C" fn handler(signal: i32) {
             let signal = match signal {
                 sys::SIGINT => signals::SIGINT,
@@ -177,7 +174,7 @@ impl ShellBuilder {
         self
     }
 
-    pub fn new() -> ShellBuilder { ShellBuilder }
+    pub fn new() -> Self { ShellBuilder }
 }
 
 impl<'a> Shell<'a> {
@@ -191,7 +188,7 @@ impl<'a> Shell<'a> {
     /// The method is non-blocking, and therefore will immediately return file handles to the
     /// stdout and stderr of the child. The PID of the child is returned, which may be used to
     /// wait for and obtain the exit status.
-    pub fn fork<F: FnMut(&mut Shell<'a>)>(
+    pub fn fork<F: FnMut(&mut Self)>(
         &self,
         capture: Capture,
         child_func: F,
@@ -224,6 +221,15 @@ impl<'a> Shell<'a> {
         }
     }
 
+    /// A method for executing literal scripts. Given a read instance, the shell will process
+    /// commands as they arrive
+    pub fn execute_script<T: std::io::Read>(&mut self, lines: T) {
+        if let Err(why) = self.execute_command(lines) {
+            eprintln!("ion: {}", why);
+            self.previous_status = FAILURE;
+        }
+    }
+
     /// A method for executing commands in the Ion shell without capturing. It takes command(s)
     /// as
     /// a string argument, parses them, and executes them the same as it would if you had
@@ -239,7 +245,13 @@ impl<'a> Shell<'a> {
         {
             self.on_command(&cmd)
         }
-        Ok(self.previous_status)
+
+        if let Some(block) = self.flow_control.unclosed_block() {
+            self.previous_status = FAILURE;
+            Err(IonError::UnclosedBlock { block: block.to_string() })
+        } else {
+            Ok(self.previous_status)
+        }
     }
 
     /// Obtains a variable, returning an empty string if it does not exist.
@@ -310,21 +322,9 @@ impl<'a> Shell<'a> {
             Some(self.execute_pipeline(pipeline))
         };
 
-        // If `RECORD_SUMMARY` is set to "1" (True, Yes), then write a summary of the
-        // pipline just executed to the the file and context histories. At the
-        // moment, this means record how long it took.
-        if let Some(context) = self.context.as_mut() {
-            if "1" == &*self.variables.get_str_or_empty("RECORD_SUMMARY") {
-                if let Ok(elapsed_time) = command_start_time.elapsed() {
-                    let summary = format!(
-                        "#summary# elapsed real time: {}.{:09} seconds",
-                        elapsed_time.as_secs(),
-                        elapsed_time.subsec_nanos()
-                    );
-                    context.history.push(summary.into()).unwrap_or_else(|err| {
-                        eprintln!("ion: history append: {}", err);
-                    });
-                }
+        if let Some(ref callback) = self.on_command {
+            if let Ok(elapsed_time) = command_start_time.elapsed() {
+                callback(self, elapsed_time);
             }
         }
 
@@ -356,29 +356,49 @@ impl<'a> Shell<'a> {
         }
     }
 
+    /// Call the cleanup callback
+    pub fn prep_for_exit(&mut self) {
+        if let Some(mut callback) = self.prep_for_exit.take() {
+            callback(self);
+        }
+    }
+
+    /// Set the callback to call before exiting the shell
+    #[inline]
+    pub fn set_prep_for_exit(&mut self, callback: Option<Box<dyn FnMut(&mut Shell) + 'a>>) {
+        self.prep_for_exit = callback;
+    }
+
+    /// Set the callback to call on each command
+    #[inline]
+    pub fn set_on_command(
+        &mut self,
+        callback: Option<Box<dyn Fn(&Shell, std::time::Duration) + 'a>>,
+    ) {
+        self.on_command = callback;
+    }
+
+    /// Get access to the builtins
+    #[inline]
+    pub fn builtins(&self) -> &BuiltinMap<'a> { &self.builtins }
+
+    /// Get a mutable access to the builtins
+    ///
+    /// Warning: Previously defined functions will rely on previous versions of the builtins, even
+    /// if they are redefined. It is strongly advised to avoid mutating the builtins while the shell
+    /// is running
+    #[inline]
+    pub fn builtins_mut(&mut self) -> &mut BuiltinMap<'a> { &mut self.builtins }
+
     /// Cleanly exit ion
     pub fn exit(&mut self, status: i32) -> ! {
         self.prep_for_exit();
         process::exit(status);
     }
 
-    pub(crate) fn prep_for_exit(&mut self) {
-        // The context has two purposes: if it exists, this is an interactive shell; and the
-        // context will also be sent a signal to commit all changes to the history file,
-        // and waiting for the history thread in the background to finish.
-        if self.context.is_some() {
-            if self.flags & HUPONEXIT != 0 {
-                self.resume_stopped();
-                self.background_send(sys::SIGHUP);
-            }
-            self.context.as_mut().unwrap().history.commit_to_file();
-        }
-    }
-
-    pub(crate) fn new(is_library: bool) -> Self {
-        let mut shell = Shell {
+    pub fn new(is_library: bool) -> Self {
+        Shell {
             builtins: BuiltinMap::default(),
-            context: None,
             variables: Variables::default(),
             flow_control: FlowControl::default(),
             directory_stack: DirectoryStack::new(),
@@ -390,11 +410,9 @@ impl<'a> Shell<'a> {
             is_library,
             break_flow: false,
             foreground_signals: Arc::new(ForegroundSignals::new()),
-            ignore_setting: IgnoreSetting::default(),
-        };
-        let ignore_patterns = shell.variables.get("HISTORY_IGNORE").unwrap();
-        shell.update_ignore_patterns(&ignore_patterns);
-        shell
+            on_command: None,
+            prep_for_exit: None,
+        }
     }
 
     pub fn assign(&mut self, key: &Key, value: Value<'a>) -> Result<(), String> {
@@ -452,7 +470,7 @@ impl<'a> Shell<'a> {
     }
 }
 
-impl<'a> Expander for Shell<'a> {
+impl<'a, 'b> Expander for Shell<'b> {
     /// Uses a subshell to expand a given command.
     fn command(&self, command: &str) -> Option<types::Str> {
         let mut output = None;
diff --git a/src/main.rs b/src/main.rs
index 9af19f77beda811d7b48b4a935b1347bd9902e09..4028e72e3d843bb1bbe729286ca40e225b3b1863 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,10 @@
 extern crate ion_sys as sys;
 
-use ion_shell::{flags::NO_EXEC, Binary, JobControl, ShellBuilder, MAN_ION};
+use ion_shell::{
+    flags::{NO_EXEC, PRINT_COMMS},
+    InteractiveBinary, JobControl, ShellBuilder, MAN_ION,
+};
+use liner::KeyBindings;
 use smallvec::SmallVec;
 use std::{
     alloc::System,
@@ -25,8 +29,26 @@ fn main() {
     let mut command = None;
     let mut args = env::args().skip(1);
     let mut script_path = None;
+    let mut key_bindings = None;
     while let Some(arg) = args.next() {
         match arg.as_str() {
+            "-o" => match args.next().as_ref().map(|s| s.as_str()) {
+                Some("vi") => {
+                    key_bindings = Some(KeyBindings::Vi);
+                }
+                Some("emacs") => {
+                    key_bindings = Some(KeyBindings::Emacs);
+                }
+                Some(_) => {
+                    eprintln!("ion: set: invalid option");
+                    return;
+                }
+                None => {
+                    eprintln!("ion: set: no option given");
+                    return;
+                }
+            },
+            "-x" => shell.flags |= PRINT_COMMS,
             "-n" | "--no-execute" => {
                 shell.flags |= NO_EXEC;
             }
@@ -63,8 +85,13 @@ fn main() {
     } else if let Some(path) = script_path {
         shell.execute_file(&path.as_str());
     } else if stdin_is_a_tty {
-        shell.execute_interactive();
-        unreachable!();
+        let mut interactive = InteractiveBinary::new(shell);
+        if let Some(key_bindings) = key_bindings {
+            interactive.set_keybindings(key_bindings);
+        }
+        interactive.init_file();
+        interactive.add_callbacks();
+        interactive.execute_interactive();
     } else {
         shell.execute_script(BufReader::new(stdin()));
     }