~rachelk/rk-fm

65eb4d38ecb1c78375424dad734d3b5726e3fae9 — Rachel K 3 years ago master
wip
A  => .gitignore +2 -0
@@ 1,2 @@
/target
**/*.rs.bk

A  => Cargo.lock +672 -0
@@ 1,672 @@
[[package]]
name = "argon2rs"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
 "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "arrayvec"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "atk"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "atk-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gobject-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "atk-sys"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gobject-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "autocfg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "backtrace"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
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.6 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
 "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "backtrace-sys"
version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "bitflags"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "blake2-rfc"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
 "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "cairo-rs"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 "cairo-sys-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gobject-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "cairo-sys-rs"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
 "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "cc"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "cfg-if"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "constant_time_eq"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "dirs"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 "redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "failure"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
 "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "failure_derive"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
 "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
 "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "fixedbitset"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "fnv"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "fragile"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "gdk"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 "cairo-rs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "cairo-sys-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gdk-pixbuf 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gdk-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gio 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gio-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gobject-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 "pango 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "gdk-pixbuf"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "gdk-pixbuf-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gio 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gio-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gobject-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "gdk-pixbuf-sys"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "gio-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gobject-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "gdk-sys"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "cairo-sys-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gdk-pixbuf-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gio-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gobject-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 "pango-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "gio"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 "fragile 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gio-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gobject-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "gio-sys"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gobject-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "glib"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gobject-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "glib-sys"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "gobject-sys"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "gtk"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "atk 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 "cairo-rs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "cairo-sys-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
 "gdk 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gdk-pixbuf 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gdk-pixbuf-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gdk-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gio 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gio-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gobject-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gtk-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 "pango 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "pango-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "gtk-sys"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "atk-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "cairo-sys-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gdk-pixbuf-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gdk-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gio-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gobject-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 "pango-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "lazy_static"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "lazy_static"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "libc"
version = "0.2.48"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "mime"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "nodrop"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "nom"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "ordermap"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "owning_ref"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "pango"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gobject-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 "pango-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "pango-sys"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gobject-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "parking_lot"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
 "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "parking_lot_core"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
 "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
 "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "petgraph"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
 "ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "pkg-config"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "proc-macro2"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "quote"
version = "0.6.11"
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.48 (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.6 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "rand_core"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "redox_syscall"
version = "0.1.51"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "redox_users"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
 "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
 "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "rk-fm"
version = "0.1.0"
dependencies = [
 "dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 "gdk-pixbuf 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gio 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "glib 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "gtk 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
 "tree_magic 0.2.1 (git+https://github.com/aahancoc/tree_magic)",
]

[[package]]
name = "rustc-demangle"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "scoped_threadpool"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "smallvec"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "stable_deref_trait"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "syn"
version = "0.15.26"
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)",
 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "synstructure"
version = "0.10.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)",
 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
 "syn 0.15.26 (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 = "tree_magic"
version = "0.2.1"
source = "git+https://github.com/aahancoc/tree_magic#9bc1f46eeda7985aa06ecb1b4f0dc8c306706f8c"
dependencies = [
 "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
 "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
 "nom 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
 "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "unicase"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "version_check"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "winapi"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[metadata]
"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
"checksum atk 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7ce8fd2055aa2ce617754c5a701682a06b4b57093cbbcbd8f068622a8debae96"
"checksum atk-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83744274abbcc2242f845a25cf84b9adb5991eaecc8f7c67cffd69ea636f4ff8"
"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4"
"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 blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
"checksum cairo-rs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e09d8a818b2ccc8983f04d95a9350c3cf8d24cc456cedca3b88fa3a81fdc0e2"
"checksum cairo-sys-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3fa13914fdc013387afa771f554f2f71d6ae931f4e5be9246c337d60c3dc484"
"checksum cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4390a3b5f4f6bce9c1d0c00128379df433e53777fdd30e92f16a529332baec4e"
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
"checksum dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "88972de891f6118092b643d85a0b28e0678e0f948d7f879aa32f2d5aafe97d2a"
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"checksum fragile 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f8140122fa0d5dcb9fc8627cfce2b37cc1500f752636d46ea28bc26785c2f9"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum gdk 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c229b642a3cf701f92246b131fda2eaabaa5f44f4a255dee65939ebd0ab0141"
"checksum gdk-pixbuf 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9a1bcb11b461ff5638f6bf03c9f173d3dc250eabc8e57a60644b6f529d3a7c91"
"checksum gdk-pixbuf-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "10e1115ca451907b6d775fc0392641d14c89277662d98828412fb68555e7e8c8"
"checksum gdk-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "458dc6243bdda4aa1693f5f18231f55b98e9c99c50b3b9bd673cf461ef1710ea"
"checksum gio 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff120a666f4a0f41cca7554fbac82defc2562e90eccf3b26a30e6461fa1bbde8"
"checksum gio-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "04957c40df00dd72f7c9ec8e382b01ff8ed4a904fcd2fa608b7ae7fbaccfda8f"
"checksum glib 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff186a0d7c1057652b96b51ee21bde4e7255812bdff62a83debf873be7d80d5c"
"checksum glib-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bda542f3caee39a027638e9644ff89204101ad916fd7370b585ad2c5fc97e61"
"checksum gobject-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23e05a14290d3dc255223cba51db4b0f3da438d5250657996fa99b2a30faf43e"
"checksum gtk 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b52cfbd8c3e4a000c8374676352f3850c2d62c0f42ef0a993e5d3fcf47e0be64"
"checksum gtk-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "849835f05d46f605b00ee9fefb6d5921238c570af406f35ee7426ed01cd6795c"
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
"checksum mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "3e27ca21f40a310bd06d9031785f4801710d566c184a6e15bad4f1d9b65f9425"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum nom 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf51a729ecf40266a2368ad335a5fdde43471f545a967109cd62146ecf8b66ff"
"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
"checksum pango 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4e36b55d7cd522bd183efeb3dfabc547bda1f26eadf8a1241dac09ab3fd3242c"
"checksum pango-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "747ab9cd4d537e6dc5ef0e4308c10dde8b706673b0237fed4e056b8d2c0b23c8"
"checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e"
"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa"
"checksum petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f"
"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
"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 rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85"
"checksum redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "214a97e49be64fd2c86f568dd0cb2c757d2cc53de95b273b6ad0a1c908482f26"
"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
"checksum tree_magic 0.2.1 (git+https://github.com/aahancoc/tree_magic)" = "<none>"
"checksum unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d3218ea14b4edcaccfa0df0a64a3792a2c32cc706f1b336e48867f9d3147f90"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

A  => Cargo.toml +17 -0
@@ 1,17 @@
[package]
name    = "rk-fm"
version = "0.1.0"
authors = ["Rachel K <raech.kanati@gmail.com>"]
edition = "2018"
build   = "build.rs"

[dependencies]
glib       = "0.7"
gtk        = { version = "0.6", features = ["v3_24"] }
gio        = "0.6"
gdk-pixbuf = "0.6"

dirs       = "1.0"
tree_magic = { git = "https://github.com/aahancoc/tree_magic" }
mime       = "0.3"


A  => build.rs +85 -0
@@ 1,85 @@

use std::{
    env,
    error::Error,
    fs,
    io::ErrorKind,
    process::{Command, Stdio},
    str,
};

fn main() {
    eprintln!(
        "Running build script with CWD {}",
        env::current_dir().unwrap().to_string_lossy()
    );

    let out_path = env::var("OUT_DIR").unwrap() + "/resources";
    let src_dir = "src/ui/resources/";
    let xml_path = src_dir.to_string() + "resources.xml";

    let out_mtime_maybe = fs::metadata(&out_path)
        .and_then(|md| md.modified());

    let need_rebuild = match out_mtime_maybe {
        // something went wrong
        Err(ref e) if e.kind() != ErrorKind::NotFound => panic!("{}", e),

        // output doesn't even exist - definitely rebuild
        Err(_) => true,

        // output exists - let's check against the manifest
        Ok(out_mtime) => {
            let xml_mtime = fs::metadata(&xml_path)
                .and_then(|md| md.modified())
                .expect("error getting input manifest mtime");

            // manifest has changed more recently than the output - rebuild
            xml_mtime > out_mtime || {
                // xml hasn't changed, but maybe the resources have
                let deps = Command::new("glib-compile-resources")
                    .args(&["--generate-dependencies", &xml_path])
                    .output()
                    .map_err(|e| -> Box<dyn Error> { e.into() })
                    .and_then(|raw: std::process::Output| {
                        str::from_utf8(&raw.stdout)
                            .map_err(|e| e.into())
                            .map(|s| s.to_string())
                    })
                    .expect("error getting input manifest dependencies");

                let mut need_rebuild = false;
                for dep in deps.lines() {
                    let dep_path = src_dir.to_string() + &dep.trim();
                    let dep_mtime = fs::metadata(&dep_path)
                        .and_then(|md| md.modified())
                        .expect("error getting input resource mtime");
                    // this resource has changed more recently than the output - rebuild
                    if dep_mtime > out_mtime {
                        need_rebuild = true;
                        break;
                    }
                }
                need_rebuild
            }
        }
    };

    if !need_rebuild { return; }

    let build_output = Command::new("glib-compile-resources")
        .args(&[
            "--generate",
            &format!("--sourcedir={}", &src_dir),
            &format!("--target={}", &out_path),
            &xml_path
        ])
        .stderr(Stdio::inherit())
        .output()
        .expect("error spawning resource build");

    if !build_output.status.success() {
        panic!("error building resource bundle");
    }
}


A  => src/main.rs +15 -0
@@ 1,15 @@

mod ui;
mod util;

use std::{
    error::Error,
    result::Result,
};

fn main() -> Result<(), Box<dyn Error>> {
    let ui = ui::UI::new()?;
    ui.run();
    Ok(())
}


A  => src/ui/controller.rs +87 -0
@@ 1,87 @@

use {
    crate::ui::{
        model::{self, Model},
        view::View,
    },
    std::{
        cell::RefCell,
        rc::Rc,
    },
    gtk::{
        Application,
    },
    gio::{
        prelude::*,
        SimpleAction,
    },
};

pub struct Controller {
    refs: Rc<RefCell<(Model, View)>>,
}

impl Controller {
    pub fn new(app: &Application, model: Model, view: View) -> Controller {
        let refs = Rc::new(RefCell::new( (model, view) ));

        static acts: [(&str, fn(&mut Model) -> model::Result<bool>); 4] = [
          ("go_up",      Model::go_up),
          ("go_home",    Model::go_home),
          ("go_back",    Model::go_back),
          ("go_forward", Model::go_forward),
        ];
        for (name, method) in &acts {
            Controller::prep_action(refs.clone(), app, name, method);
        }

        {   let (ref model, ref mut view) = *refs.borrow_mut();
            view.connect_on_item_activated(Controller::on_select_folder(refs.clone()));
            Self::maybe_update_view(view, model.render().map(Some));
        }

        Controller { refs }
    }

    fn maybe_update_view(view: &mut View, result: model::Result<Option<model::Rendered>>) {
        match result {
            Ok(maybe_rendered) => if let Some(rendered) = maybe_rendered {
                view.update(rendered);
            },
            Err(e) => { eprintln!("{}", e); }
        }
    }

    fn prep_action(
        refs: Rc<RefCell<(Model, View)>>,
        app: &Application,
        name: &str,
        f: impl Fn(&mut Model) -> model::Result<bool> + 'static)
    -> SimpleAction {
        let act = SimpleAction::new(name, None);
        act.connect_activate(move |_,_| {
            let (ref mut model, ref mut view) = *refs.borrow_mut();
            let result = f(model)
                .and_then(|changed|
                    if changed { model.render().map(Some) }
                    else       { Ok(None) }
                );
            Self::maybe_update_view(view, result);
        });
        app.add_action(&act);
        act
    }

    fn on_select_folder(refs: Rc<RefCell<(Model, View)>>) -> impl Fn(&str) {
        move |name| {
            let (ref mut model, ref mut view) = *refs.borrow_mut();
            let result = model
                .select_folder(name)
                .and_then(|changed|
                    if changed { model.render().map(Some) }
                    else       { Ok(None) }
                );
            Self::maybe_update_view(view, result);
        }
    }
}

A  => src/ui/mod.rs +120 -0
@@ 1,120 @@

mod model;
mod view;
mod controller;
mod resources;

use {
    crate::ui::{
        model::Model,
        view::View,
        controller::Controller,
    },
    std::{
        cell::RefCell,
        error::Error,
        result::Result,
    },
    gtk::{
        prelude::*,
        AboutDialog,
        Application,
        ApplicationWindow,
        BuildableExt,
        Builder,
        ButtonBox,
        DialogExt,
        IconView,
        Object,
    },
    gio::{
        prelude::*,
        resources_register,
        ApplicationFlags,
        Resource,
        SimpleAction,
    },
};

static APPLICATION_ID: &str = "io.github.rkanati.file_manager";

pub struct UI {
//  model:      Model,
//  view:       View,
    controller: Controller,
}

impl UI {
    pub fn new() -> Result<UI, Box<dyn Error>> {
        resources_register(
            &Resource::new_from_data(&resources::BUNDLE.into())?
        );

        let app = Application::new(APPLICATION_ID, ApplicationFlags::NON_UNIQUE)?;
        eprintln!("resource base path: {}", app.get_resource_base_path().unwrap());
        app.connect_startup(|_| { });

        // XXX workaround type ambiguity
        let nunn: Option<&gio::Cancellable> = None;
        app.register(nunn)?;

        // Load UI
        let builder = Builder::new_from_resource("/io/github/rkanati/file_manager/ui.glade");
        fn build<R: IsA<Object>>(b: &Builder, name: &str) -> R { b.get_object(name).expect(name) }

        let window:    ApplicationWindow    = build(&builder, "window-app");
        let icon_view: IconView             = build(&builder, "icon-view");
        let about_ref: RefCell<AboutDialog> = RefCell::new(build(&builder, "window-about"));
        let path_bar:  ButtonBox            = build(&builder, "path-bar");

        window.set_property("application", &app.to_value())?;

        // Actions
        let on_quit = SimpleAction::new("quit", None);
        on_quit.connect_activate(|_,_| { gtk::main_quit(); });
        app.add_action(&on_quit);
        app.set_accels_for_action("app.quit", &["<Ctrl>q"]);

        let on_show_about = SimpleAction::new("show_about", None);
        on_show_about.connect_activate({
            let about = about_ref.clone();
            move |_,_| { about.borrow().run(); }
        });
        app.add_action(&on_show_about);

        let accels = [
            ("app.go_up",      ["<Ctrl>u"]),
            ("app.go_home",    ["<Ctrl>h"]),
            ("app.go_back",    ["<Ctrl>p"]),
            ("app.go_forward", ["<Ctrl>n"]),
        ];
        for (act, accels) in &accels {
            app.set_accels_for_action(act, accels);
        }

        window.connect_delete_event(|_, _| {
            gtk::main_quit();
            // Let the default handler destroy the window.
            Inhibit(false)
        });

        about_ref.borrow().connect_delete_event(|about, _| {
            about.hide();
            // Don't destroy
            Inhibit(true)
        });

        window.show_all();

        let model = Model::new()?;
        let view = View::new(icon_view, window.upcast(), path_bar)?;
        let controller = Controller::new(&app, model, view);

        Ok(UI { controller })
    }

    pub fn run(&self) {
        gtk::main();
    }
}


A  => src/ui/model.rs +187 -0
@@ 1,187 @@

use {
    crate::util::{
        HistoryZipper,
        mime
    },
    std::{
        error::Error as StdError,
        fmt,
        io,
        path::{Path, PathBuf},
        result::Result as StdResult,
    },
    dirs,
    glib,
    gtk::{
        prelude::*,
        IconLookupFlags,
        IconTheme,
        IconThemeExt,
        ListStore,
        Type as GType,
    },
    gdk_pixbuf::Pixbuf,
};

#[derive(Debug)]
pub enum Error {
    IO(io::Error),
    Glib(glib::Error),
    Other(Box<dyn StdError>),
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Error { Error::IO(e) }
}

impl From<Box<dyn StdError>> for Error {
    fn from(e: Box<dyn StdError>) -> Error { Error::Other(e) }
}

impl From<glib::Error> for Error {
    fn from(e: glib::Error) -> Error { Error::Glib(e) }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Error: ")?;
        match self {
            Error::IO(e)    => e.fmt(f),
            Error::Glib(e)  => e.fmt(f),
            Error::Other(e) => e.fmt(f)
        }
    }
}

impl StdError for Error { }

pub type Result<T> = StdResult<T, Error>;

struct Store { }

impl Store {
    fn new() -> Store {
        Store { }
    }

    fn go(&mut self, path: &Path) -> io::Result<()> {
        std::env::set_current_dir(&path)
    }
}

pub struct Renderer {
    icon_theme:  IconTheme,
    folder_icon: Pixbuf,
    file_icon:   Pixbuf,
}

pub struct Rendered {
    pub store: ListStore,
    pub path:  PathBuf,
}

impl Renderer {
    fn new() -> Result<Renderer> {
        let icon_theme = IconTheme::get_default().expect("error getting icon theme");
        let folder_icon = icon_theme
            .load_icon("folder", 48, IconLookupFlags::FORCE_REGULAR)?
            .expect("no `folder` icon in current gtk+ icon theme");
        let file_icon = icon_theme
            .load_icon("unknown", 48, IconLookupFlags::FORCE_REGULAR)?
            .expect("no `unknown` icon in current gtk+ icon theme");
        Ok(Renderer { icon_theme, folder_icon, file_icon })
    }

    fn render(&self, _store: &Store) -> Result<Rendered> {
        let columns = [GType::String, Pixbuf::static_type()];
        let store = ListStore::new(&columns);
        for entry in std::fs::read_dir(".")? {
            let entry = entry?;

            // get filename
            let name: String = entry.file_name().to_string_lossy().into();
            if name.starts_with(".") { continue; }

            // choose icon
            let icon = if entry.file_type()?.is_dir() {
                &self.folder_icon
            }
            else {
                &self.file_icon
            };

            let iter = store.append();
            store.set_value(&iter, 0, &(&name).into());
            store.set_value(&iter, 1, &(&icon).into());
        }

        let path = std::env::current_dir()
            .and_then(|path| path.canonicalize())
            .unwrap();
        //  .to_string_lossy();
        //  .into();

        Ok(Rendered { store, path })
    }
}

fn home_dir() -> PathBuf {
    dirs::home_dir().unwrap_or("/".into())
}

pub struct Model {
    history:  HistoryZipper<PathBuf>,
    store:    Store,
    renderer: Renderer,
}

impl Model {
    pub fn new() -> Result<Model> {
        Ok(Model {
            history:  HistoryZipper::new(std::env::current_dir().unwrap_or(home_dir())),
            store:    Store::new(),
            renderer: Renderer::new()?
        })
    }

    pub fn render(&self) -> Result<Rendered> {
        eprintln!("{:?}", self.history);
        self.renderer.render(&self.store)
    }

    fn go(&mut self, f: impl FnOnce(&mut HistoryZipper<PathBuf>) -> bool) -> Result<bool> {
        if f(&mut self.history) {
            self.store.go(&self.history.now())?;
            Ok(true)
        }
        else {
            Ok(false)
        }
    }

    pub fn go_back(&mut self) -> Result<bool> {
        self.go(HistoryZipper::back)
    }

    pub fn go_forward(&mut self) -> Result<bool> {
        self.go(HistoryZipper::forward)
    }

    pub fn go_to(&mut self, path: impl Into<PathBuf>) -> Result<bool> {
        let path: PathBuf = path.into().canonicalize()?;
        self.go(move |hz| hz.go(path))
    }

    pub fn go_up(&mut self) -> Result<bool> {
        self.go_to("..")
    }

    pub fn go_home(&mut self) -> Result<bool> {
        self.go_to(home_dir())
    }

    pub fn select_folder(&mut self, name: &str) -> Result<bool> {
        self.go_to(format!("./{}", name))
    }
}

A  => src/ui/resources/gtk/menus.ui +12 -0
@@ 1,12 @@
<?xml version="1.0"?>
<interface>
  <menu id="app-menu">
    <section>
      <item>
        <attribute name="label" translatable="yes">_Quit</attribute>
        <attribute name="action">app.quit</attribute>
      </item>
    </section>
  </menu>
</interface>


A  => src/ui/resources/mod.rs +3 -0
@@ 1,3 @@

pub static BUNDLE: &[u8] = include_bytes!(concat![env!("OUT_DIR"), "/resources"]);


A  => src/ui/resources/resources.xml +8 -0
@@ 1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
  <gresource prefix="/io/github/rkanati/file_manager">
    <file>gtk/menus.ui</file>
    <file>ui.glade</file>
  </gresource>
</gresources>


A  => src/ui/resources/ui.glade +214 -0
@@ 1,214 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkAdjustment" id="adjust-h-icon-view">
    <property name="upper">100</property>
    <property name="step_increment">1</property>
    <property name="page_increment">10</property>
  </object>
  <object class="GtkAdjustment" id="adjust-v-icon-view">
    <property name="upper">100</property>
    <property name="step_increment">1</property>
    <property name="page_increment">10</property>
  </object>
  <object class="GtkImage" id="icon-back">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="icon_name">go-previous-symbolic</property>
    <property name="icon_size">2</property>
  </object>
  <object class="GtkImage" id="icon-forward">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="icon_name">go-next-symbolic</property>
    <property name="icon_size">2</property>
  </object>
  <object class="GtkImage" id="icon-home">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="icon_name">user-home-symbolic</property>
    <property name="icon_size">2</property>
  </object>
  <object class="GtkImage" id="icon-up">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="icon_name">go-up-symbolic</property>
    <property name="icon_size">2</property>
  </object>
  <object class="GtkMenu" id="menu-dots">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <child>
      <object class="GtkMenuItem" id="menu-dots-about">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="action_name">app.show_about</property>
        <property name="label" translatable="yes">About</property>
        <property name="use_underline">True</property>
      </object>
    </child>
  </object>
  <object class="GtkApplicationWindow" id="window-app">
    <property name="can_focus">False</property>
    <property name="icon_name">system-file-manager</property>
    <property name="show_menubar">False</property>
    <child type="titlebar">
      <object class="GtkHeaderBar" id="header-bar">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="has_subtitle">False</property>
        <property name="show_close_button">True</property>
        <child>
          <object class="GtkButton" id="button-go-back">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="receives_default">True</property>
            <property name="action_name">app.go_back</property>
            <property name="image">icon-back</property>
            <property name="always_show_image">True</property>
          </object>
          <packing>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="button-go-forward">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="receives_default">True</property>
            <property name="action_name">app.go_forward</property>
            <property name="image">icon-forward</property>
            <property name="always_show_image">True</property>
          </object>
          <packing>
            <property name="position">2</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="button-go-up">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="receives_default">True</property>
            <property name="action_name">app.go_up</property>
            <property name="image">icon-up</property>
            <property name="always_show_image">True</property>
          </object>
          <packing>
            <property name="position">3</property>
          </packing>
        </child>
        <child>
          <object class="GtkButtonBox" id="path-bar">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="layout_style">start</property>
            <child>
              <placeholder/>
            </child>
          </object>
          <packing>
            <property name="position">4</property>
          </packing>
        </child>
        <child>
          <object class="GtkMenuButton" id="menu-button-dots">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <property name="popup">menu-dots</property>
            <property name="use_popover">False</property>
            <child>
              <object class="GtkImage">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="icon_name">open-menu-symbolic</property>
              </object>
            </child>
          </object>
          <packing>
            <property name="pack_type">end</property>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="button-go-home">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="receives_default">True</property>
            <property name="action_name">app.go_home</property>
            <property name="image">icon-home</property>
            <property name="always_show_image">True</property>
          </object>
          <packing>
            <property name="pack_type">end</property>
            <property name="position">2</property>
          </packing>
        </child>
      </object>
    </child>
    <child>
      <object class="GtkScrolledWindow" id="scroll-icon-view">
        <property name="visible">True</property>
        <property name="can_focus">True</property>
        <property name="hadjustment">adjust-h-icon-view</property>
        <property name="vadjustment">adjust-v-icon-view</property>
        <property name="shadow_type">in</property>
        <child>
          <object class="GtkIconView" id="icon-view">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="margin">0</property>
            <property name="hadjustment">adjust-h-icon-view</property>
            <property name="hscroll_policy">natural</property>
            <property name="vadjustment">adjust-v-icon-view</property>
            <property name="vscroll_policy">natural</property>
            <property name="selection_mode">multiple</property>
          </object>
        </child>
      </object>
    </child>
  </object>
  <object class="GtkAboutDialog" id="window-about">
    <property name="can_focus">False</property>
    <property name="window_position">center</property>
    <property name="type_hint">dialog</property>
    <property name="transient_for">window-app</property>
    <property name="program_name">rk-fm</property>
    <property name="version">0.1.0</property>
    <property name="copyright" translatable="yes">(C) 2019 Rachel K</property>
    <property name="comments" translatable="yes">A work-in-progress file manager</property>
    <property name="website">https://git.sr.ht/~rachelk/rk-fm</property>
    <property name="website_label" translatable="yes">Git repository</property>
    <property name="authors">Rachel K</property>
    <property name="logo_icon_name">system-file-manager</property>
    <property name="license_type">agpl-3-0</property>
    <child type="titlebar">
      <placeholder/>
    </child>
    <child internal-child="vbox">
      <object class="GtkBox">
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <property name="spacing">2</property>
        <child internal-child="action_area">
          <object class="GtkButtonBox">
            <property name="can_focus">False</property>
            <property name="layout_style">end</property>
            <child>
              <placeholder/>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">False</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <placeholder/>
        </child>
      </object>
    </child>
  </object>
</interface>

A  => src/ui/view.rs +82 -0
@@ 1,82 @@

use {
    crate::ui::model,
    std::{
        error::Error,
        path::Component,
    },
    gtk::{
        prelude::*,
        Align,
        ButtonBox,
        IconView,
        ListStore,
        RadioButton,
        Type as GType,
        Window,
    },
};

pub struct View {
    icon_view: IconView,
    window:    Window,
    path_bar:  ButtonBox,
}

fn path_seg(path_bar: &ButtonBox, group: &mut Option<RadioButton>, label: String) {
    let seg = RadioButton::new_with_label(&label);
    seg.set_focus_on_click(false);
    seg.set_size_request(-1, 40);
    seg.set_property_draw_indicator(false);
    seg.set_active(false);
    path_bar.pack_start(&seg.clone(), false, true, 0);
    path_bar.set_child_non_homogeneous(&seg.clone(), true);
    if group.is_none() {
        *group = Some(seg.clone());
    }
    seg.join_group(Some(&seg.clone()));
}

impl View {
    pub fn new(icon_view: IconView, window: Window, path_bar: ButtonBox)
        -> Result<View, Box<dyn Error>>
    {
        icon_view.set_text_column(0);
        icon_view.set_pixbuf_column(1);

        Ok(View { icon_view, window, path_bar })
    }

    pub fn connect_on_item_activated(&mut self, f: impl Fn(&str) + 'static) {
        self.icon_view.connect_item_activated(move |icon_view, tree_path| {
            let store: ListStore = icon_view.get_model().unwrap().downcast().unwrap();
            let iter = store.get_iter(tree_path).unwrap();
            let name: String = store.get_value(&iter, 0).get().unwrap();
            f(&name)
        });
    }

    pub fn update(&mut self, rendered: model::Rendered) {
        // update the icon view
        self.icon_view.set_model(Some(&rendered.store.clone()));

        // update the path bar - first, get rid of all the old segments
        self.path_bar.foreach(|ref seg| { seg.destroy(); });

        // now add in new ones
        let mut group: Option<RadioButton> = None;
        for cmp in rendered.path.components() {
            match cmp {
                Component::RootDir => {
                    path_seg(&self.path_bar, &mut group, "/".to_string());
                },
                Component::Normal(c) => {
                    path_seg(&self.path_bar, &mut group, c.to_string_lossy().into());
                },
                _ => { }
            }
        }

        self.path_bar.show_all();
    }
}

A  => src/util/history_zipper.rs +53 -0
@@ 1,53 @@

#[derive(Debug)]
pub struct HistoryZipper<T> {
    buffer: Vec<T>,
    index:  usize
}

impl<T: PartialEq + Clone> HistoryZipper<T> {
    pub fn new(now: impl Into<T>) -> HistoryZipper<T> {
        HistoryZipper {
            buffer: vec![now.into()],
            index:  0
        }
    }

    pub fn now(&self) -> T {
        self.buffer[self.index].clone()
    }

    pub fn back(&mut self) -> bool {
        if self.index > 0 {
            self.index -= 1;
            true
        }
        else {
            false
        }
    }

    pub fn forward(&mut self) -> bool {
        if self.index + 1 < self.buffer.len() {
            self.index += 1;
            true
        }
        else {
            false
        }
    }

    pub fn go(&mut self, to: impl Into<T>) -> bool {
        let to: T = to.into();
        if to != self.now() {
            self.buffer.truncate(self.index + 1);
            self.buffer.push(to.into());
            self.forward();
            true
        }
        else {
            false
        }
    }
}


A  => src/util/mime.rs +77 -0
@@ 1,77 @@

use {
    std::{
        fs,
        io,
        os::unix::fs::FileTypeExt,
        path::Path,
        str::FromStr,
    },
    tree_magic,
    mime
};

pub use mime::Mime;

pub enum Type {
    Directory,
    BlockDevice,
    CharacterDevice,
    Pipe,
    Socket,
    Regular(Mime),
}

pub struct Meta {
    meta:      fs::Metadata,
    ty:        Type,
    link_meta: Option<fs::Metadata>
}

impl Meta {
    pub fn is_symlink(&self) -> bool {
        self.link_meta.is_some()
    }
}

impl Type {
    pub fn is_dir(&self) -> bool {
        if let Type::Directory = self { true }
        else                          { false }
    }

    pub fn is_regular(&self) -> bool {
        if let Type::Regular(_) = self { true }
        else                           { false }
    }
}

pub fn get_metadata(path: &Path) -> io::Result<Meta> {
    let (meta, link_meta) = {
        let meta = fs::symlink_metadata(path)?;
        if meta.file_type().is_symlink() {
            (fs::metadata(path)?, Some(meta))
        }
        else {
            (meta, None)
        }
    };

    let ty = {
        let file_type = meta.file_type();
        match file_type {
            ft if ft.is_dir()          => Type::Directory,
            ft if ft.is_block_device() => Type::BlockDevice,
            ft if ft.is_char_device()  => Type::CharacterDevice,
            ft if ft.is_fifo()         => Type::Pipe,
            ft if ft.is_socket()       => Type::Socket,
            _ => {
                // TODO mime sniff
                Type::Regular(Mime::from_str("application/octet-stream").unwrap())
            }
        }
    };

    Ok(Meta { meta, ty, link_meta })
}


A  => src/util/mod.rs +6 -0
@@ 1,6 @@

pub mod history_zipper;
pub use history_zipper::*;

pub mod mime;