Merge branch 'master' into ext_cmdline
This commit is contained in:
commit
f8bce73ac0
268
Cargo.lock
generated
268
Cargo.lock
generated
@ -8,12 +8,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "atk-sys"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -50,25 +50,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cairo-rs"
|
||||
version = "0.3.0"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"c_vec 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-sys-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-sys-rs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cairo-sys-rs"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -118,103 +117,106 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "gdk"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-sys-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-pixbuf 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-sys-rs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-pixbuf 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gdk-pixbuf"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gdk-pixbuf-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-pixbuf-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gdk-pixbuf-sys"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gdk-sys"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-sys-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-pixbuf-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-sys-rs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-pixbuf-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gio"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gio-sys"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib-sys"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -224,52 +226,53 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gobject-sys"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gtk"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-sys-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-pixbuf 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-pixbuf-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gtk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-sys-rs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-pixbuf 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-pixbuf-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gtk-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gtk-sys"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"atk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atk-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-sys-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-pixbuf-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-sys-rs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-pixbuf-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -364,25 +367,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
name = "nvim-gtk"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"cairo-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gtk 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gtk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdk-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gio 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gtk 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gtk-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"htmlescape 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"neovim-lib 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pangocairo 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pangocairo-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pangocairo 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pangocairo-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rmpv 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -392,59 +398,64 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pango"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pango-sys"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pangocairo"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-sys-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-sys-rs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pangocairo-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pangocairo-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pangocairo-sys"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-sys-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cairo-sys-rs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pango-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.7.21"
|
||||
@ -702,11 +713,6 @@ name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.4"
|
||||
@ -736,31 +742,31 @@ dependencies = [
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
|
||||
"checksum atk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "33a67fd81e1922dddc335887516f2f5254534e89c9d39fa89bca5d79bd150d34"
|
||||
"checksum atk-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8dc233521f7bffd3042c31082ea71bd08820abf44bac938fb36591e20f76f39"
|
||||
"checksum atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8352656fd42c30a0c3c89d26dea01e3b77c0ab2af18230835c15e2e13cd51859"
|
||||
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
||||
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
|
||||
"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
|
||||
"checksum c_vec 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6237ac5a4b1e81c213c24c6437964c61e646df910a914b4ab1487b46df20bd13"
|
||||
"checksum cairo-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6b5695f59fd036fe5741bc5a4eb20c78fbe42256e3b08a2af26bbcbe8070bf3"
|
||||
"checksum cairo-sys-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6e18fecaeac51809db57f45f4553cc0975225a7eb435a7a7e91e5e8113a84d"
|
||||
"checksum cairo-rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a110f269c2fd382df5fe8bd46dfa5f1b83608aa717fecb6e7a28c08c202f0e13"
|
||||
"checksum cairo-sys-rs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0395175ecba60accac076a02c31d143b9dcd9d5eb5316d7163a3273803b765c7"
|
||||
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
||||
"checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9"
|
||||
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
|
||||
"checksum env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f15f0b172cb4f52ed5dbf47f774a387cd2315d1bf7894ab5af9b083ae27efa5a"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum gdk 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e51db95be6565011bcd5cd99f9b17fdd585001057a999b21e09f1e8c28deb9"
|
||||
"checksum gdk-pixbuf 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16160d212ae91abe9f3324c3fb233929ba322dde63585d15cda3336f8c529ed1"
|
||||
"checksum gdk-pixbuf-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "798f97101eea8180da363d0e80e07ec7ec6d1809306601c0100c1de5bc8b4f52"
|
||||
"checksum gdk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4ee916f5f25c5f4b21bd9dcb12a216ae697406940ff9476358c308a8ececada"
|
||||
"checksum gio 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "84ba5a2beb559059a0c9c2bd3681743cdede8d9a36c775840bca800333b22867"
|
||||
"checksum gio-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a303bbf7a5e75ab3b627117ff10e495d1b9e97e1d68966285ac2b1f6270091bc"
|
||||
"checksum glib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9b0452824cc63066940f01adc721804919f0b76cdba3cfab977b00b87f16d4a"
|
||||
"checksum glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9693049613ff52b93013cc3d2590366d8e530366d288438724b73f6c7dc4be8"
|
||||
"checksum gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60d507c87a71b1143c66ed21a969be9b99a76df234b342d733e787e6c9c7d7c2"
|
||||
"checksum gtk 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0847c507e52c1feaede13ef56fb4847742438602655449d5f1f782e8633f146f"
|
||||
"checksum gtk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "905fcfbaaad1b44ec0b4bba9e4d527d728284c62bc2ba41fccedace2b096766f"
|
||||
"checksum gdk 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd30051ff3d908ff2fc7e5776ffe1c699821e043809f294c3a61004f11d6c3a9"
|
||||
"checksum gdk-pixbuf 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c2d2199eba47ebcb9977ce28179649bdd59305ef465c4e6f9b65aaa41c24e6b5"
|
||||
"checksum gdk-pixbuf-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df6a3b73e04fafc07f5ebc083f1096a773412e627828e1103a55e921f81187d8"
|
||||
"checksum gdk-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3162ff940526ddff71bf1f630facee6b5e05d282d125ba0c4c803842819b80c3"
|
||||
"checksum gio 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "071fd4e5592b39fdc31318e32d2497842501f539bcedb60c75cd365946642adc"
|
||||
"checksum gio-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2a57872499171d279f8577ce83837da4cae62b08dd32892236ed67ab7ea61030"
|
||||
"checksum glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e0be1b1432e227bcd1a9b28db9dc1474a7e7fd4227e08e16f35304f32d09b61"
|
||||
"checksum glib-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615bef979b5838526aee99241afc80cfb2e34a8735d4bcb8ec6072598c18a408"
|
||||
"checksum gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70409d6405db8b1591602fcd0cbe8af52cd9976dd39194442b4c149ba343f86d"
|
||||
"checksum gtk 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "414f3522f550a0b4f65e089f00ffcd3987dab8b0be284cb979aa7f6a03d60516"
|
||||
"checksum gtk-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d9554cf5b3a85a13fb39258c65b04b262989c1d7a758f8f555b77a478621a91"
|
||||
"checksum htmlescape 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163"
|
||||
"checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c"
|
||||
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
|
||||
@ -773,10 +779,11 @@ dependencies = [
|
||||
"checksum num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "4b226df12c5a59b63569dd57fafb926d91b385dfce33d8074a412411b689d593"
|
||||
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
||||
"checksum num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7de20f146db9d920c45ee8ed8f71681fd9ade71909b48c3acbd766aa504cf10"
|
||||
"checksum pango 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e81c404ab81ea7ea2fc2431a0a7672507b80e4b8bf4b41eac3fc83cc665104e"
|
||||
"checksum pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34f34a1be107fe16abb2744e0e206bee4b3b07460b5fddd3009a6aaf60bd69ab"
|
||||
"checksum pangocairo 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "41a8620ece55098d741bacf4d3aa52398f85ce83cfe0d8f670fa11de88f52c40"
|
||||
"checksum pangocairo-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e34ec010b38a2a6dafdf3d86ffe1251a0ae759208ec85f78c66c0445481bd5a8"
|
||||
"checksum pango 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45374801e224373c3c0393cd48073c81093494c8735721e81d1dbaa4096b2767"
|
||||
"checksum pango-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94039b3921a4af4058a3e4335e5d15099101f298a92f5afc40bab3a3027594a1"
|
||||
"checksum pangocairo 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db4130d0e0567b177178c9568466277ff167cb43a245b2881e203509ea5fbd84"
|
||||
"checksum pangocairo-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "decc9523cd5bbba49a67ed8d2ef7dfca957f4760bf420a1ea4a82634da26381c"
|
||||
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
|
||||
"checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc"
|
||||
"checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f"
|
||||
"checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03"
|
||||
@ -809,7 +816,6 @@ dependencies = [
|
||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3"
|
||||
"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"
|
||||
|
29
Cargo.toml
29
Cargo.toml
@ -5,17 +5,17 @@ authors = ["daa84 <daa84@inbox.ru>"]
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
cairo-rs = "0.3"
|
||||
pango = "0.3"
|
||||
pango-sys = "0.5"
|
||||
pangocairo = "0.4"
|
||||
pangocairo-sys = "0.6"
|
||||
glib = "0.4"
|
||||
glib-sys = "0.5"
|
||||
gdk = "0.7"
|
||||
gdk-sys = "0.5"
|
||||
gio = "0.3"
|
||||
gobject-sys = "0.5"
|
||||
cairo-rs = "0.4"
|
||||
pango = "0.4"
|
||||
pango-sys = "0.6"
|
||||
pangocairo = "0.5"
|
||||
pangocairo-sys = "0.7"
|
||||
glib = "0.5"
|
||||
glib-sys = "0.6"
|
||||
gdk = "0.8"
|
||||
gdk-sys = "0.6"
|
||||
gio = "0.4"
|
||||
gobject-sys = "0.6"
|
||||
#gdk = { git = 'https://github.com/gtk-rs/gdk' }
|
||||
#gdk-sys = { git = 'https://github.com/gtk-rs/sys' }
|
||||
#glib = { git = 'https://github.com/gtk-rs/glib' }
|
||||
@ -32,6 +32,9 @@ log = "0.4"
|
||||
env_logger = "0.5"
|
||||
htmlescape = "0.3"
|
||||
rmpv = "0.4"
|
||||
percent-encoding = "1.0"
|
||||
regex = "0.2"
|
||||
lazy_static = "1.0"
|
||||
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
@ -45,12 +48,12 @@ serde_json = "1.0"
|
||||
phf_codegen = "0.7"
|
||||
|
||||
[dependencies.gtk]
|
||||
version = "0.3"
|
||||
version = "0.4"
|
||||
features = ["v3_22"]
|
||||
#git = "https://github.com/gtk-rs/gtk"
|
||||
|
||||
[dependencies.gtk-sys]
|
||||
version = "0.5"
|
||||
version = "0.6"
|
||||
features = ["v3_22"]
|
||||
#git = 'https://github.com/gtk-rs/sys'
|
||||
|
||||
|
141
resources/side-panel.ui
Normal file
141
resources/side-panel.ui
Normal file
@ -0,0 +1,141 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.20.4 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.8"/>
|
||||
<object class="GtkTreeStore" id="dir_list_model">
|
||||
<columns>
|
||||
<!-- column-name dir_name -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name icon_name -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name path -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkMenu" id="file_browser_context_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkMenuItem">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="action_name">filebrowser.cd</property>
|
||||
<property name="label" translatable="yes">Go To Directory</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="action_name">filebrowser.reload</property>
|
||||
<property name="label" translatable="yes">Reload</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckMenuItem" id="file_browser_show_hidden_checkbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label">Show Hidden Files</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkTreeStore" id="file_browser_tree_store">
|
||||
<columns>
|
||||
<!-- column-name filename -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name path -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name file_type -->
|
||||
<column type="guchar"/>
|
||||
<!-- column-name icon_name -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkBox" id="file_browser">
|
||||
<property name="width_request">150</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkComboBox" id="dir_list">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="border_width">6</property>
|
||||
<property name="model">dir_list_model</property>
|
||||
<property name="wrap_width">1</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererPixbuf">
|
||||
<property name="xpad">6</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="icon-name">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<property name="xpad">6</property>
|
||||
<property name="ellipsize">end</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="file_browser_tree_view">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="model">file_browser_tree_store</property>
|
||||
<property name="headers_visible">False</property>
|
||||
<property name="show_expanders">False</property>
|
||||
<property name="level_indentation">20</property>
|
||||
<property name="activate_on_single_click">True</property>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection"/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn">
|
||||
<property name="sizing">autosize</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererPixbuf">
|
||||
<property name="xpad">6</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="icon-name">3</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCellRendererText"/>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="view"/>
|
||||
</style>
|
||||
</object>
|
||||
</interface>
|
Binary file not shown.
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 91 KiB |
551
src/file_browser.rs
Normal file
551
src/file_browser.rs
Normal file
@ -0,0 +1,551 @@
|
||||
use std::cell::RefCell;
|
||||
use std::cmp::Ordering;
|
||||
use std::io;
|
||||
use std::fs;
|
||||
use std::fs::DirEntry;
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
use std::rc::Rc;
|
||||
use std::ops::Deref;
|
||||
|
||||
use gio;
|
||||
use gio::prelude::*;
|
||||
use gtk;
|
||||
use gtk::MenuExt;
|
||||
use gtk::prelude::*;
|
||||
|
||||
use neovim_lib::{NeovimApi, NeovimApiAsync};
|
||||
|
||||
use misc::escape_filename;
|
||||
use nvim::{ErrorReport, NeovimClient, NeovimRef};
|
||||
use shell;
|
||||
|
||||
const ICON_FOLDER_CLOSED: &str = "folder-symbolic";
|
||||
const ICON_FOLDER_OPEN: &str = "folder-open-symbolic";
|
||||
const ICON_FILE: &str = "text-x-generic-symbolic";
|
||||
|
||||
struct Components {
|
||||
dir_list_model: gtk::TreeStore,
|
||||
dir_list: gtk::ComboBox,
|
||||
context_menu: gtk::Menu,
|
||||
show_hidden_checkbox: gtk::CheckMenuItem,
|
||||
cd_action: gio::SimpleAction,
|
||||
}
|
||||
|
||||
struct State {
|
||||
current_dir: String,
|
||||
show_hidden: bool,
|
||||
selected_path: Option<String>,
|
||||
}
|
||||
|
||||
pub struct FileBrowserWidget {
|
||||
store: gtk::TreeStore,
|
||||
tree: gtk::TreeView,
|
||||
widget: gtk::Box,
|
||||
nvim: Option<Rc<NeovimClient>>,
|
||||
comps: Components,
|
||||
state: Rc<RefCell<State>>,
|
||||
}
|
||||
|
||||
impl Deref for FileBrowserWidget {
|
||||
type Target = gtk::Box;
|
||||
|
||||
fn deref(&self) -> >k::Box {
|
||||
&self.widget
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum FileType {
|
||||
File,
|
||||
Dir,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
enum Column {
|
||||
Filename,
|
||||
Path,
|
||||
FileType,
|
||||
IconName,
|
||||
}
|
||||
|
||||
impl FileBrowserWidget {
|
||||
pub fn new() -> Self {
|
||||
let builder = gtk::Builder::new_from_string(include_str!("../resources/side-panel.ui"));
|
||||
let widget: gtk::Box = builder.get_object("file_browser").unwrap();
|
||||
let tree: gtk::TreeView = builder.get_object("file_browser_tree_view").unwrap();
|
||||
let store: gtk::TreeStore = builder.get_object("file_browser_tree_store").unwrap();
|
||||
let dir_list_model: gtk::TreeStore = builder.get_object("dir_list_model").unwrap();
|
||||
let dir_list: gtk::ComboBox = builder.get_object("dir_list").unwrap();
|
||||
let context_menu: gtk::Menu = builder.get_object("file_browser_context_menu").unwrap();
|
||||
let show_hidden_checkbox: gtk::CheckMenuItem = builder
|
||||
.get_object("file_browser_show_hidden_checkbox")
|
||||
.unwrap();
|
||||
|
||||
let file_browser = FileBrowserWidget {
|
||||
store,
|
||||
tree,
|
||||
widget,
|
||||
nvim: None,
|
||||
comps: Components {
|
||||
dir_list_model,
|
||||
dir_list,
|
||||
context_menu,
|
||||
show_hidden_checkbox,
|
||||
cd_action: gio::SimpleAction::new("cd", None),
|
||||
},
|
||||
state: Rc::new(RefCell::new(State {
|
||||
current_dir: "".to_owned(),
|
||||
show_hidden: false,
|
||||
selected_path: None,
|
||||
})),
|
||||
};
|
||||
file_browser
|
||||
}
|
||||
|
||||
fn nvim(&self) -> Option<NeovimRef> {
|
||||
self.nvim.as_ref().unwrap().nvim()
|
||||
}
|
||||
|
||||
pub fn init(&mut self, shell_state: &shell::State) {
|
||||
// Initialize values.
|
||||
let nvim = shell_state.nvim_clone();
|
||||
self.nvim = Some(nvim);
|
||||
if let Some(dir) = get_current_dir(&mut self.nvim().unwrap()) {
|
||||
update_dir_list(&dir, &self.comps.dir_list_model, &self.comps.dir_list);
|
||||
self.state.borrow_mut().current_dir = dir;
|
||||
}
|
||||
|
||||
// Populate tree.
|
||||
tree_reload(&self.store, &self.state.borrow());
|
||||
|
||||
let store = &self.store;
|
||||
let state_ref = &self.state;
|
||||
self.tree.connect_test_expand_row(clone!(store, state_ref => move |_, iter, _| {
|
||||
store.set(&iter, &[Column::IconName as u32], &[&ICON_FOLDER_OPEN]);
|
||||
// We cannot recursively populate all directories. Instead, we have prepared a single
|
||||
// empty child entry for all non-empty directories, so the row will be expandable. Now,
|
||||
// when a directory is expanded, populate its children.
|
||||
let state = state_ref.borrow();
|
||||
if let Some(child) = store.iter_children(iter) {
|
||||
let filename = store.get_value(&child, Column::Filename as i32);
|
||||
if filename.get::<&str>().is_none() {
|
||||
store.remove(&child);
|
||||
let dir_value = store.get_value(&iter, Column::Path as i32);
|
||||
if let Some(dir) = dir_value.get() {
|
||||
populate_tree_nodes(&store, &state, dir, Some(iter));
|
||||
}
|
||||
} else {
|
||||
// This directory is already populated, i.e. it has been expanded and collapsed
|
||||
// again. Rows further down the tree might have been silently collapsed without
|
||||
// getting an event. Update their folder icon.
|
||||
let mut tree_path = store.get_path(&child).unwrap();
|
||||
while let Some(iter) = store.get_iter(&tree_path) {
|
||||
tree_path.next();
|
||||
let file_type = store
|
||||
.get_value(&iter, Column::FileType as i32)
|
||||
.get::<u8>();
|
||||
if file_type == Some(FileType::Dir as u8) {
|
||||
store.set(&iter, &[Column::IconName as u32], &[&ICON_FOLDER_CLOSED]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Inhibit(false)
|
||||
}));
|
||||
|
||||
self.tree.connect_row_collapsed(clone!(store => move |_, iter, _| {
|
||||
store.set(&iter, &[Column::IconName as u32], &[&ICON_FOLDER_CLOSED]);
|
||||
}));
|
||||
|
||||
// Further initialization.
|
||||
self.init_actions();
|
||||
self.init_subscriptions(shell_state);
|
||||
self.connect_events();
|
||||
}
|
||||
|
||||
fn init_actions(&self) {
|
||||
let actions = gio::SimpleActionGroup::new();
|
||||
|
||||
let store = &self.store;
|
||||
let state_ref = &self.state;
|
||||
let nvim_ref = self.nvim.as_ref().unwrap();
|
||||
|
||||
let reload_action = gio::SimpleAction::new("reload", None);
|
||||
reload_action.connect_activate(clone!(store, state_ref => move |_, _| {
|
||||
tree_reload(&store, &state_ref.borrow());
|
||||
}));
|
||||
actions.add_action(&reload_action);
|
||||
|
||||
let cd_action = &self.comps.cd_action;
|
||||
cd_action.connect_activate(clone!(state_ref, nvim_ref => move |_, _| {
|
||||
let mut nvim = nvim_ref.nvim().unwrap();
|
||||
if let Some(ref path) = state_ref.borrow().selected_path {
|
||||
nvim.set_current_dir(&path).report_err();
|
||||
}
|
||||
}));
|
||||
actions.add_action(cd_action);
|
||||
|
||||
self.comps
|
||||
.context_menu
|
||||
.insert_action_group("filebrowser", &actions);
|
||||
}
|
||||
|
||||
fn init_subscriptions(&self, shell_state: &shell::State) {
|
||||
// Always set the current working directory as the root of the file browser.
|
||||
let store = &self.store;
|
||||
let state_ref = &self.state;
|
||||
let dir_list_model = &self.comps.dir_list_model;
|
||||
let dir_list = &self.comps.dir_list;
|
||||
shell_state.subscribe(
|
||||
"DirChanged",
|
||||
&["getcwd()"],
|
||||
clone!(store, state_ref, dir_list_model, dir_list => move |args| {
|
||||
let dir = args.into_iter().next().unwrap();
|
||||
let mut state = state_ref.borrow_mut();
|
||||
if dir != *state.current_dir {
|
||||
update_dir_list(&dir, &dir_list_model, &dir_list);
|
||||
state.current_dir = dir;
|
||||
tree_reload(&store, &state);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
// Reveal the file of an entered buffer in the file browser and select the entry.
|
||||
let tree = &self.tree;
|
||||
let subscription = shell_state.subscribe(
|
||||
"BufEnter",
|
||||
&["getcwd()", "expand('%:p')"],
|
||||
clone!(tree, store => move |args| {
|
||||
let mut args_iter = args.into_iter();
|
||||
let dir = args_iter.next().unwrap();
|
||||
let file_path = args_iter.next().unwrap();
|
||||
let could_reveal =
|
||||
if let Ok(rel_path) = Path::new(&file_path).strip_prefix(&Path::new(&dir)) {
|
||||
reveal_path_in_tree(&store, &tree, &rel_path)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if !could_reveal {
|
||||
tree.get_selection().unselect_all();
|
||||
}
|
||||
}),
|
||||
);
|
||||
shell_state.run_now(&subscription);
|
||||
}
|
||||
|
||||
fn connect_events(&self) {
|
||||
// Open file / go to dir, when user clicks on an entry.
|
||||
let store = &self.store;
|
||||
let state_ref = &self.state;
|
||||
let nvim_ref = self.nvim.as_ref().unwrap();
|
||||
self.tree.connect_row_activated(clone!(store, state_ref, nvim_ref => move |tree, path, _| {
|
||||
let iter = store.get_iter(path).unwrap();
|
||||
let file_type = store
|
||||
.get_value(&iter, Column::FileType as i32)
|
||||
.get::<u8>()
|
||||
.unwrap();
|
||||
let file_path = store
|
||||
.get_value(&iter, Column::Path as i32)
|
||||
.get::<String>()
|
||||
.unwrap();
|
||||
if file_type == FileType::Dir as u8 {
|
||||
let expanded = tree.row_expanded(path);
|
||||
if expanded {
|
||||
tree.collapse_row(path);
|
||||
} else {
|
||||
tree.expand_row(path, false);
|
||||
}
|
||||
} else {
|
||||
// FileType::File
|
||||
let cwd = &state_ref.borrow().current_dir;
|
||||
let cwd = Path::new(cwd);
|
||||
let file_path = if let Some(rel_path) = Path::new(&file_path)
|
||||
.strip_prefix(&cwd)
|
||||
.ok()
|
||||
.and_then(|p| p.to_str())
|
||||
{
|
||||
rel_path
|
||||
} else {
|
||||
&file_path
|
||||
};
|
||||
let file_path = escape_filename(file_path);
|
||||
nvim_ref.nvim().unwrap().command_async(&format!(":e {}", file_path))
|
||||
.cb(|r| r.report_err())
|
||||
.call();
|
||||
}
|
||||
}));
|
||||
|
||||
// Connect directory list.
|
||||
let nvim_ref = self.nvim.as_ref().unwrap();
|
||||
self.comps.dir_list.connect_changed(clone!(nvim_ref => move |dir_list| {
|
||||
if let Some(iter) = dir_list.get_active_iter() {
|
||||
let model = dir_list.get_model().unwrap();
|
||||
if let Some(dir) = model.get_value(&iter, 2).get::<&str>() {
|
||||
let mut nvim = nvim_ref.nvim().unwrap();
|
||||
nvim.set_current_dir(dir).report_err();
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
let store = &self.store;
|
||||
let state_ref = &self.state;
|
||||
let context_menu = &self.comps.context_menu;
|
||||
let cd_action = &self.comps.cd_action;
|
||||
self.tree.connect_button_press_event(
|
||||
clone!(store, state_ref, context_menu, cd_action => move |tree, ev_btn| {
|
||||
// Open context menu on right click.
|
||||
if ev_btn.get_button() == 3 {
|
||||
context_menu.popup_at_pointer(&**ev_btn);
|
||||
let (pos_x, pos_y) = ev_btn.get_position();
|
||||
let iter = tree
|
||||
.get_path_at_pos(pos_x as i32, pos_y as i32)
|
||||
.and_then(|(path, _, _, _)| path)
|
||||
.and_then(|path| store.get_iter(&path));
|
||||
let file_type = iter
|
||||
.as_ref()
|
||||
.and_then(|iter| {
|
||||
store
|
||||
.get_value(&iter, Column::FileType as i32)
|
||||
.get::<u8>()
|
||||
});
|
||||
// Enable the "Go To Directory" action only if the user clicked on a folder.
|
||||
cd_action.set_enabled(file_type == Some(FileType::Dir as u8));
|
||||
let path = iter
|
||||
.and_then(|iter| {
|
||||
store
|
||||
.get_value(&iter, Column::Path as i32)
|
||||
.get::<String>()
|
||||
});
|
||||
state_ref.borrow_mut().selected_path = path;
|
||||
}
|
||||
Inhibit(false)
|
||||
}),
|
||||
);
|
||||
|
||||
// Show / hide hidden files when corresponding menu item is toggled.
|
||||
self.comps.show_hidden_checkbox.connect_toggled(clone!(state_ref, store => move |ev| {
|
||||
let mut state = state_ref.borrow_mut();
|
||||
state.show_hidden = ev.get_active();
|
||||
tree_reload(&store, &state);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/// Compare function for dir entries.
|
||||
///
|
||||
/// Sorts directories above files.
|
||||
fn cmp_dirs_first(lhs: &DirEntry, rhs: &DirEntry) -> io::Result<Ordering> {
|
||||
let lhs_metadata = fs::metadata(lhs.path())?;
|
||||
let rhs_metadata = fs::metadata(rhs.path())?;
|
||||
if lhs_metadata.file_type() == rhs_metadata.file_type() {
|
||||
Ok(lhs.path().cmp(&rhs.path()))
|
||||
} else {
|
||||
if lhs_metadata.is_dir() {
|
||||
Ok(Ordering::Less)
|
||||
} else {
|
||||
Ok(Ordering::Greater)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears an repopulate the entire tree.
|
||||
fn tree_reload(store: >k::TreeStore, state: &State) {
|
||||
let dir = &state.current_dir;
|
||||
store.clear();
|
||||
populate_tree_nodes(store, state, dir, None);
|
||||
}
|
||||
|
||||
/// Updates the dirctory list on top of the file browser.
|
||||
///
|
||||
/// The list represents the path the the current working directory. If the new cwd is a parent of
|
||||
/// the old one, the list is kept and only the active entry is updated. Otherwise, the list is
|
||||
/// replaced with the new path and the last entry is marked active.
|
||||
fn update_dir_list(dir: &str, dir_list_model: >k::TreeStore, dir_list: >k::ComboBox) {
|
||||
// The current working directory path.
|
||||
let complete_path = Path::new(dir);
|
||||
let mut path = PathBuf::new();
|
||||
let mut components = complete_path.components();
|
||||
let mut next = components.next();
|
||||
|
||||
// Iterator over existing dir_list model.
|
||||
let mut dir_list_iter = dir_list_model.get_iter_first();
|
||||
|
||||
// Whether existing entries up to the current position of dir_list_iter are a prefix of the
|
||||
// new current working directory path.
|
||||
let mut is_prefix = true;
|
||||
|
||||
// Iterate over components of the cwd. Simultaneously move dir_list_iter forward.
|
||||
while let Some(dir) = next {
|
||||
next = components.next();
|
||||
let dir_name = &*dir.as_os_str().to_string_lossy();
|
||||
// Assemble path up to current component.
|
||||
path.push(Path::new(&dir));
|
||||
let path_str = path.to_str().unwrap_or_else(|| {
|
||||
error!(
|
||||
"Could not convert path to string: {}\n
|
||||
Directory chooser will not work for that entry.",
|
||||
path.to_string_lossy()
|
||||
);
|
||||
""
|
||||
});
|
||||
// Use the current entry of dir_list, if any, otherwise append a new one.
|
||||
let current_iter = dir_list_iter.unwrap_or_else(|| dir_list_model.append(None));
|
||||
// Check if the current entry is still part of the new cwd.
|
||||
if is_prefix && dir_list_model.get_value(¤t_iter, 0).get::<&str>() != Some(&dir_name)
|
||||
{
|
||||
is_prefix = false;
|
||||
}
|
||||
if next.is_some() {
|
||||
// Update dir_list entry.
|
||||
dir_list_model.set(
|
||||
¤t_iter,
|
||||
&[0, 1, 2],
|
||||
&[&dir_name, &ICON_FOLDER_CLOSED, &path_str],
|
||||
);
|
||||
} else {
|
||||
// We reached the last component of the new cwd path. Set the active entry of dir_list
|
||||
// to this one.
|
||||
dir_list_model.set(
|
||||
¤t_iter,
|
||||
&[0, 1, 2],
|
||||
&[&dir_name, &ICON_FOLDER_OPEN, &path_str],
|
||||
);
|
||||
dir_list.set_active_iter(¤t_iter);
|
||||
};
|
||||
// Advance dir_list_iter.
|
||||
dir_list_iter = if dir_list_model.iter_next(¤t_iter) {
|
||||
Some(current_iter)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
// We updated the dir list to the point of the current working directory.
|
||||
if let Some(iter) = dir_list_iter {
|
||||
if is_prefix {
|
||||
// If we didn't change any entries to this point and the list contains further entries,
|
||||
// the remaining ones are subdirectories of the cwd and we keep them.
|
||||
loop {
|
||||
dir_list_model.set(&iter, &[1], &[&ICON_FOLDER_CLOSED]);
|
||||
if !dir_list_model.iter_next(&iter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If we needed to change entries, the following ones are not directories under the
|
||||
// cwd and we clear them.
|
||||
while dir_list_model.remove(&iter) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Populates one level, i.e. one directory of the file browser tree.
|
||||
fn populate_tree_nodes(
|
||||
store: >k::TreeStore,
|
||||
state: &State,
|
||||
dir: &str,
|
||||
parent: Option<>k::TreeIter>,
|
||||
) {
|
||||
let path = Path::new(dir);
|
||||
let read_dir = match path.read_dir() {
|
||||
Ok(read_dir) => read_dir,
|
||||
Err(err) => {
|
||||
error!("Couldn't populate tree: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let iter = read_dir.filter_map(Result::ok);
|
||||
let mut entries: Vec<DirEntry> = if state.show_hidden {
|
||||
iter.collect()
|
||||
} else {
|
||||
iter.filter(|entry| !entry.file_name().to_string_lossy().starts_with("."))
|
||||
.filter(|entry| !entry.file_name().to_string_lossy().ends_with("~"))
|
||||
.collect()
|
||||
};
|
||||
entries.sort_unstable_by(|lhs, rhs| cmp_dirs_first(lhs, rhs).unwrap_or(Ordering::Equal));
|
||||
for entry in entries {
|
||||
let path = if let Some(path) = entry.path().to_str() {
|
||||
path.to_owned()
|
||||
} else {
|
||||
// Skip paths that contain invalid unicode.
|
||||
continue;
|
||||
};
|
||||
let filename = entry.file_name().to_str().unwrap().to_owned();
|
||||
let file_type = if let Ok(metadata) = fs::metadata(entry.path()) {
|
||||
let file_type = metadata.file_type();
|
||||
if file_type.is_dir() {
|
||||
FileType::Dir
|
||||
} else if file_type.is_file() {
|
||||
FileType::File
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// In case of invalid symlinks, we cannot obtain metadata.
|
||||
continue;
|
||||
};
|
||||
let icon = match file_type {
|
||||
FileType::Dir => ICON_FOLDER_CLOSED,
|
||||
FileType::File => ICON_FILE,
|
||||
};
|
||||
// When we get until here, we want to show the entry. Append it to the tree.
|
||||
let iter = store.append(parent);
|
||||
store.set(
|
||||
&iter,
|
||||
&[0, 1, 2, 3],
|
||||
&[&filename, &path, &(file_type as u8), &icon],
|
||||
);
|
||||
// For directories, check whether the directory is empty. If not, append a single empty
|
||||
// entry, so the expand arrow is shown. Its contents are dynamically populated when
|
||||
// expanded (see `init`).
|
||||
if let FileType::Dir = file_type {
|
||||
let not_empty = if let Ok(mut dir) = entry.path().read_dir() {
|
||||
dir.next().is_some()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if not_empty {
|
||||
let iter = store.append(&iter);
|
||||
store.set(&iter, &[], &[]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_current_dir(nvim: &mut NeovimRef) -> Option<String> {
|
||||
match nvim.eval("getcwd()") {
|
||||
Ok(cwd) => cwd.as_str().map(|s| s.to_owned()),
|
||||
Err(err) => {
|
||||
error!("Couldn't get cwd: {}", err);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reveals and selects the given file in the file browser.
|
||||
///
|
||||
/// Returns `true` if the file could be successfully revealed.
|
||||
fn reveal_path_in_tree(store: >k::TreeStore, tree: >k::TreeView, rel_file_path: &Path) -> bool {
|
||||
let mut tree_path = gtk::TreePath::new();
|
||||
'components: for component in rel_file_path.components() {
|
||||
if let Component::Normal(component) = component {
|
||||
tree_path.down();
|
||||
while let Some(iter) = store.get_iter(&tree_path) {
|
||||
let entry_value = store.get_value(&iter, Column::Filename as i32);
|
||||
let entry = entry_value.get::<&str>().unwrap();
|
||||
if component == entry {
|
||||
tree.expand_row(&tree_path, false);
|
||||
continue 'components;
|
||||
}
|
||||
tree_path.next();
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if tree_path.get_depth() == 0 {
|
||||
return false;
|
||||
}
|
||||
tree.set_cursor(&tree_path, None, false);
|
||||
true
|
||||
}
|
27
src/main.rs
27
src/main.rs
@ -11,14 +11,18 @@ extern crate gtk;
|
||||
extern crate gtk_sys;
|
||||
extern crate htmlescape;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate neovim_lib;
|
||||
extern crate pango;
|
||||
extern crate pango_cairo_sys;
|
||||
extern crate pango_sys;
|
||||
extern crate pangocairo;
|
||||
extern crate percent_encoding;
|
||||
extern crate phf;
|
||||
extern crate rmpv;
|
||||
extern crate regex;
|
||||
|
||||
extern crate serde;
|
||||
#[macro_use]
|
||||
@ -50,6 +54,9 @@ mod popup_menu;
|
||||
mod project;
|
||||
mod tabline;
|
||||
mod error;
|
||||
mod file_browser;
|
||||
mod subscriptions;
|
||||
mod misc;
|
||||
|
||||
use std::env;
|
||||
use std::time::Duration;
|
||||
@ -98,21 +105,23 @@ fn main() {
|
||||
}
|
||||
|
||||
fn open(app: >k::Application, files: &[gio::File], _: &str) {
|
||||
for f in files {
|
||||
let mut ui = Ui::new(ShellOptions::new(
|
||||
nvim_bin_path(std::env::args()),
|
||||
f.get_path().and_then(|p| p.to_str().map(str::to_owned)),
|
||||
nvim_timeout(std::env::args()),
|
||||
));
|
||||
let files_list: Vec<String> = files
|
||||
.into_iter()
|
||||
.filter_map(|f| f.get_path()?.to_str().map(str::to_owned))
|
||||
.collect();
|
||||
let mut ui = Ui::new(ShellOptions::new(
|
||||
nvim_bin_path(std::env::args()),
|
||||
files_list,
|
||||
nvim_timeout(std::env::args()),
|
||||
));
|
||||
|
||||
ui.init(app, !nvim_disable_win_state(std::env::args()));
|
||||
}
|
||||
ui.init(app, !nvim_disable_win_state(std::env::args()));
|
||||
}
|
||||
|
||||
fn activate(app: >k::Application) {
|
||||
let mut ui = Ui::new(ShellOptions::new(
|
||||
nvim_bin_path(std::env::args()),
|
||||
None,
|
||||
Vec::new(),
|
||||
nvim_timeout(std::env::args()),
|
||||
));
|
||||
|
||||
|
38
src/misc.rs
Normal file
38
src/misc.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use regex::Regex;
|
||||
use percent_encoding::percent_decode;
|
||||
|
||||
/// Escape special ASCII characters with a backslash.
|
||||
pub fn escape_filename<'t>(filename: &'t str) -> Cow<'t, str> {
|
||||
lazy_static! {
|
||||
static ref SPECIAL_CHARS: Regex = if cfg!(target_os = "windows") {
|
||||
// On Windows, don't escape `:` and `\`, as these are valid components of the path.
|
||||
Regex::new(r"[[:ascii:]&&[^0-9a-zA-Z._:\\-]]").unwrap()
|
||||
} else {
|
||||
// Similarly, don't escape `/` on other platforms.
|
||||
Regex::new(r"[[:ascii:]&&[^0-9a-zA-Z._/-]]").unwrap()
|
||||
};
|
||||
}
|
||||
SPECIAL_CHARS.replace_all(&*filename, r"\$0")
|
||||
}
|
||||
|
||||
/// Decode a file URI.
|
||||
///
|
||||
/// - On UNIX: `file:///path/to/a%20file.ext` -> `/path/to/a file.ext`
|
||||
/// - On Windows: `file:///C:/path/to/a%20file.ext` -> `C:\path\to\a file.ext`
|
||||
pub fn decode_uri(uri: &str) -> Option<String> {
|
||||
let path = match uri.split_at(8) {
|
||||
("file:///", path) => path,
|
||||
_ => return None,
|
||||
};
|
||||
let path = percent_decode(path.as_bytes()).decode_utf8().ok()?;
|
||||
if cfg!(target_os = "windows") {
|
||||
lazy_static! {
|
||||
static ref SLASH: Regex = Regex::new(r"/").unwrap();
|
||||
}
|
||||
Some(String::from(SLASH.replace_all(&*path, r"\")))
|
||||
} else {
|
||||
Some("/".to_owned() + &path)
|
||||
}
|
||||
}
|
@ -83,6 +83,12 @@ impl NvimHandler {
|
||||
error!("Unsupported event {:?}", params);
|
||||
}
|
||||
}
|
||||
"subscription" => {
|
||||
self.safe_call(move |ui| {
|
||||
let ui = &ui.borrow();
|
||||
ui.notify(params)
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
error!("Notification {}({:?})", method, params);
|
||||
}
|
||||
@ -130,7 +136,7 @@ impl NvimHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn safe_call<F>(&self, cb: F)
|
||||
where
|
||||
F: FnOnce(&Arc<UiMutex<shell::State>>) -> result::Result<(), String> + 'static + Send,
|
||||
|
@ -20,8 +20,9 @@ use std::result;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use neovim_lib::{Neovim, NeovimApi, Session, UiAttachOptions};
|
||||
use neovim_lib::{Neovim, NeovimApi, NeovimApiAsync, Session, UiAttachOptions};
|
||||
|
||||
use misc::escape_filename;
|
||||
use ui::UiMutex;
|
||||
use shell;
|
||||
use nvim_config::NvimConfig;
|
||||
@ -138,7 +139,7 @@ pub fn start(
|
||||
|
||||
pub fn post_start_init(
|
||||
nvim: NeovimClientAsync,
|
||||
open_path: Option<&String>,
|
||||
open_paths: Vec<String>,
|
||||
cols: u64,
|
||||
rows: u64,
|
||||
) -> result::Result<(), NvimInitError> {
|
||||
@ -159,11 +160,18 @@ pub fn post_start_init(
|
||||
.command("runtime! ginit.vim")
|
||||
.map_err(NvimInitError::new_post_init)?;
|
||||
|
||||
if let Some(path) = open_path {
|
||||
if !open_paths.is_empty() {
|
||||
let command = open_paths
|
||||
.iter()
|
||||
.fold(":ar".to_owned(), |command, filename| {
|
||||
let filename = escape_filename(filename);
|
||||
command + " " + &filename
|
||||
});
|
||||
nvim.borrow()
|
||||
.unwrap()
|
||||
.command(&format!("e {}", path))
|
||||
.map_err(NvimInitError::new_post_init)?;
|
||||
.command_async(&command)
|
||||
.cb(|r| r.report_err())
|
||||
.call();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use neovim_lib::NeovimApi;
|
||||
use neovim_lib::{NeovimApi, NeovimApiAsync};
|
||||
|
||||
use nvim::{NeovimClient, ErrorReport, NeovimRef};
|
||||
use value::ValueMapExt;
|
||||
@ -84,7 +84,9 @@ impl Manager {
|
||||
|
||||
pub fn reload(&self, path: &str) {
|
||||
if let Some(mut nvim) = self.nvim() {
|
||||
nvim.command(&format!("source {}", path)).report_err();
|
||||
nvim.command_async(&format!("source {}", path))
|
||||
.cb(|r| r.report_err())
|
||||
.call()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ pub struct Projects {
|
||||
}
|
||||
|
||||
impl Projects {
|
||||
pub fn new(ref_widget: >k::ToolButton, shell: Rc<RefCell<Shell>>) -> Rc<RefCell<Projects>> {
|
||||
pub fn new(ref_widget: >k::Button, shell: Rc<RefCell<Shell>>) -> Rc<RefCell<Projects>> {
|
||||
let projects = Projects {
|
||||
shell,
|
||||
popup: Popover::new(Some(ref_widget)),
|
||||
|
83
src/shell.rs
83
src/shell.rs
@ -19,6 +19,7 @@ use pangocairo;
|
||||
use neovim_lib::{Neovim, NeovimApi, NeovimApiAsync, Value};
|
||||
use neovim_lib::neovim_api::Tabpage;
|
||||
|
||||
use misc::{decode_uri, escape_filename};
|
||||
use settings::{FontSource, Settings};
|
||||
use ui_model::{Attrs, ModelRect, UiModel};
|
||||
use color::{Color, ColorModel, COLOR_BLACK, COLOR_RED, COLOR_WHITE};
|
||||
@ -35,6 +36,7 @@ use error;
|
||||
use mode;
|
||||
use render;
|
||||
use render::CellMetrics;
|
||||
use subscriptions::{SubscriptionHandle, Subscriptions};
|
||||
|
||||
const DEFAULT_FONT_NAME: &str = "DejaVu Sans Mono 12";
|
||||
pub const MINIMUM_SUPPORTED_NVIM_VERSION: &str = "0.2.2";
|
||||
@ -96,6 +98,8 @@ pub struct State {
|
||||
|
||||
detach_cb: Option<Box<RefCell<FnMut() + Send + 'static>>>,
|
||||
nvim_started_cb: Option<Box<RefCell<FnMut() + Send + 'static>>>,
|
||||
|
||||
subscriptions: RefCell<Subscriptions>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
@ -135,6 +139,8 @@ impl State {
|
||||
|
||||
detach_cb: None,
|
||||
nvim_started_cb: None,
|
||||
|
||||
subscriptions: RefCell::new(Subscriptions::new()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,13 +203,17 @@ impl State {
|
||||
|
||||
pub fn open_file(&self, path: &str) {
|
||||
if let Some(mut nvim) = self.nvim() {
|
||||
nvim.command(&format!("e {}", path)).report_err();
|
||||
nvim.command_async(&format!("e {}", path))
|
||||
.cb(|r| r.report_err())
|
||||
.call();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cd(&self, path: &str) {
|
||||
if let Some(mut nvim) = self.nvim() {
|
||||
nvim.command(&format!("cd {}", path)).report_err();
|
||||
nvim.command_async(&format!("cd {}", path))
|
||||
.cb(|r| r.report_err())
|
||||
.call();
|
||||
}
|
||||
}
|
||||
|
||||
@ -360,6 +370,31 @@ impl State {
|
||||
fn max_popup_width(&self) -> i32 {
|
||||
self.drawing_area.get_allocated_width() - 20
|
||||
}
|
||||
|
||||
pub fn subscribe<F>(&self, event_name: &str, args: &[&str], cb: F) -> SubscriptionHandle
|
||||
where
|
||||
F: Fn(Vec<String>) + 'static,
|
||||
{
|
||||
self.subscriptions
|
||||
.borrow_mut()
|
||||
.subscribe(event_name, args, cb)
|
||||
}
|
||||
|
||||
pub fn set_autocmds(&self) {
|
||||
self.subscriptions
|
||||
.borrow()
|
||||
.set_autocmds(&mut self.nvim().unwrap());
|
||||
}
|
||||
|
||||
pub fn notify(&self, params: Vec<Value>) -> Result<(), String> {
|
||||
self.subscriptions.borrow().notify(params)
|
||||
}
|
||||
|
||||
pub fn run_now(&self, handle: &SubscriptionHandle) {
|
||||
self.subscriptions
|
||||
.borrow()
|
||||
.run_now(handle, &mut self.nvim().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UiState {
|
||||
@ -379,19 +414,19 @@ impl UiState {
|
||||
#[derive(Clone)]
|
||||
pub struct ShellOptions {
|
||||
nvim_bin_path: Option<String>,
|
||||
open_path: Option<String>,
|
||||
open_paths: Vec<String>,
|
||||
timeout: Option<Duration>,
|
||||
}
|
||||
|
||||
impl ShellOptions {
|
||||
pub fn new(
|
||||
nvim_bin_path: Option<String>,
|
||||
open_path: Option<String>,
|
||||
open_paths: Vec<String>,
|
||||
timeout: Option<Duration>,
|
||||
) -> Self {
|
||||
ShellOptions {
|
||||
nvim_bin_path,
|
||||
open_path,
|
||||
open_paths,
|
||||
timeout,
|
||||
}
|
||||
}
|
||||
@ -565,6 +600,29 @@ impl Shell {
|
||||
state.drawing_area.connect_size_allocate(move |_, _| {
|
||||
init_nvim(&ref_state);
|
||||
});
|
||||
|
||||
let ref_state = self.state.clone();
|
||||
let targets = vec![
|
||||
gtk::TargetEntry::new("text/uri-list", gtk::TargetFlags::OTHER_APP, 0),
|
||||
];
|
||||
state
|
||||
.drawing_area
|
||||
.drag_dest_set(gtk::DestDefaults::ALL, &targets, gdk::DragAction::COPY);
|
||||
state
|
||||
.drawing_area
|
||||
.connect_drag_data_received(move |_, _, _, _, s, _, _| {
|
||||
let uris = s.get_uris();
|
||||
let command = uris.iter().filter_map(|uri| decode_uri(uri)).fold(
|
||||
":ar".to_owned(),
|
||||
|command, filename| {
|
||||
let filename = escape_filename(&filename);
|
||||
command + " " + &filename
|
||||
},
|
||||
);
|
||||
let state = ref_state.borrow_mut();
|
||||
let mut nvim = state.nvim().unwrap();
|
||||
nvim.command_async(&command).cb(|r| r.report_err()).call()
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
@ -602,7 +660,16 @@ impl Shell {
|
||||
|
||||
let nvim = state.nvim();
|
||||
if let Some(mut nvim) = nvim {
|
||||
nvim.command(":wa").report_err();
|
||||
nvim.command_async(":wa").cb(|r| r.report_err()).call();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_tab(&self) {
|
||||
let state = self.state.borrow();
|
||||
|
||||
let nvim = state.nvim();
|
||||
if let Some(mut nvim) = nvim {
|
||||
nvim.command_async(":tabe").cb(|r| r.report_err()).call();
|
||||
}
|
||||
}
|
||||
|
||||
@ -852,9 +919,7 @@ fn init_nvim_async(
|
||||
});
|
||||
|
||||
// attach ui
|
||||
if let Err(err) =
|
||||
nvim::post_start_init(nvim, options.open_path.as_ref(), cols as u64, rows as u64)
|
||||
{
|
||||
if let Err(err) = nvim::post_start_init(nvim, options.open_paths, cols as u64, rows as u64) {
|
||||
show_nvim_init_error(&err, state_arc.clone());
|
||||
} else {
|
||||
set_nvim_initialized(state_arc);
|
||||
|
156
src/subscriptions.rs
Normal file
156
src/subscriptions.rs
Normal file
@ -0,0 +1,156 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use neovim_lib::{NeovimApi, NeovimApiAsync, Value};
|
||||
|
||||
use nvim::{ErrorReport, NeovimRef};
|
||||
|
||||
/// A subscription to a Neovim autocmd event.
|
||||
struct Subscription {
|
||||
/// A callback to be executed each time the event triggers.
|
||||
cb: Box<Fn(Vec<String>) + 'static>,
|
||||
/// A list of expressions which will be evaluated when the event triggers. The result is passed
|
||||
/// to the callback.
|
||||
args: Vec<String>,
|
||||
}
|
||||
|
||||
/// A map of all registered subscriptions.
|
||||
pub struct Subscriptions(HashMap<String, Vec<Subscription>>);
|
||||
|
||||
/// A handle to identify a `Subscription` within the `Subscriptions` map.
|
||||
///
|
||||
/// Can be used to trigger the subscription manually even when the event was not triggered.
|
||||
///
|
||||
/// Could be used in the future to suspend individual subscriptions.
|
||||
#[derive(Debug)]
|
||||
pub struct SubscriptionHandle {
|
||||
event_name: String,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl Subscriptions {
|
||||
pub fn new() -> Self {
|
||||
Subscriptions(HashMap::new())
|
||||
}
|
||||
|
||||
/// Subscribe to a Neovim autocmd event.
|
||||
///
|
||||
/// Subscriptions are not active immediately but only after `set_autocmds` is called. At the
|
||||
/// moment, all calls to `subscribe` must be made before calling `set_autocmds`.
|
||||
///
|
||||
/// This function is wrapped by `shell::State`.
|
||||
///
|
||||
/// # Arguments:
|
||||
///
|
||||
/// - `event_name`: The event to register.
|
||||
/// See `:help autocmd-events` for a list of supported event names. Event names can be
|
||||
/// comma-separated.
|
||||
///
|
||||
/// - `args`: A list of expressions to be evaluated when the event triggers.
|
||||
/// Expressions are evaluated using Vimscript. The results are passed to the callback as a
|
||||
/// list of Strings.
|
||||
/// This is especially useful as `Neovim::eval` is synchronous and might block if called from
|
||||
/// the callback function; so always use the `args` mechanism instead.
|
||||
///
|
||||
/// - `cb`: The callback function.
|
||||
/// This will be called each time the event triggers or when `run_now` is called.
|
||||
/// It is passed a vector with the results of the evaluated expressions given with `args`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Call a function each time a buffer is entered or the current working directory is changed.
|
||||
/// Pass the current buffer name and directory to the callback.
|
||||
/// ```
|
||||
/// let my_subscription = shell.state.borrow()
|
||||
/// .subscribe("BufEnter,DirChanged", &["expand(@%)", "getcwd()"], move |args| {
|
||||
/// let filename = &args[0];
|
||||
/// let dir = &args[1];
|
||||
/// // do stuff
|
||||
/// });
|
||||
/// ```
|
||||
pub fn subscribe<F>(&mut self, event_name: &str, args: &[&str], cb: F) -> SubscriptionHandle
|
||||
where
|
||||
F: Fn(Vec<String>) + 'static,
|
||||
{
|
||||
let entry = self.0.entry(event_name.to_owned()).or_insert(Vec::new());
|
||||
let index = entry.len();
|
||||
entry.push(Subscription {
|
||||
cb: Box::new(cb),
|
||||
args: args.into_iter().map(|&s| s.to_owned()).collect(),
|
||||
});
|
||||
SubscriptionHandle {
|
||||
event_name: event_name.to_owned(),
|
||||
index,
|
||||
}
|
||||
}
|
||||
|
||||
/// Register all subscriptions with Neovim.
|
||||
///
|
||||
/// This function is wrapped by `shell::State`.
|
||||
pub fn set_autocmds(&self, nvim: &mut NeovimRef) {
|
||||
for (event_name, subscriptions) in &self.0 {
|
||||
for (i, subscription) in subscriptions.iter().enumerate() {
|
||||
let args = subscription
|
||||
.args
|
||||
.iter()
|
||||
.fold("".to_owned(), |acc, arg| acc + ", " + &arg);
|
||||
nvim.command_async(&format!(
|
||||
"au {} * call rpcnotify(1, 'subscription', '{}', {} {})",
|
||||
event_name, event_name, i, args,
|
||||
)).cb(|r| r.report_err())
|
||||
.call();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Trigger given event.
|
||||
fn on_notify(&self, event_name: &str, index: usize, args: Vec<String>) {
|
||||
if let Some(subscription) = self.0.get(event_name).and_then(|v| v.get(index)) {
|
||||
(*subscription.cb)(args);
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper around `on_notify` for easy calling with a `neovim_lib::Handler` implementation.
|
||||
///
|
||||
/// This function is wrapped by `shell::State`.
|
||||
pub fn notify(&self, params: Vec<Value>) -> Result<(), String> {
|
||||
let mut params_iter = params.into_iter();
|
||||
let ev_name = params_iter.next();
|
||||
let ev_name = ev_name
|
||||
.as_ref()
|
||||
.and_then(Value::as_str)
|
||||
.ok_or("Error reading event name")?;
|
||||
let index = params_iter
|
||||
.next()
|
||||
.and_then(|i| i.as_u64())
|
||||
.ok_or("Error reading index")? as usize;
|
||||
let args = params_iter
|
||||
.map(|arg| arg.as_str().map(|s| s.to_owned()))
|
||||
.collect::<Option<Vec<String>>>()
|
||||
.ok_or("Error reading args")?;
|
||||
self.on_notify(ev_name, index, args);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Manually trigger the given subscription.
|
||||
///
|
||||
/// The `nvim` instance is needed to evaluate the `args` expressions.
|
||||
///
|
||||
/// This function is wrapped by `shell::State`.
|
||||
pub fn run_now(&self, handle: &SubscriptionHandle, nvim: &mut NeovimRef) {
|
||||
let subscription = &self.0.get(&handle.event_name).unwrap()[handle.index];
|
||||
let args = subscription
|
||||
.args
|
||||
.iter()
|
||||
.map(|arg| nvim.eval(arg))
|
||||
.map(|res| {
|
||||
res.ok()
|
||||
.and_then(|val| val.as_str().map(|s: &str| s.to_owned()))
|
||||
})
|
||||
.collect::<Option<Vec<String>>>();
|
||||
if let Some(args) = args {
|
||||
self.on_notify(&handle.event_name, handle.index, args);
|
||||
} else {
|
||||
error!("Error manually running {:?}", handle);
|
||||
}
|
||||
}
|
||||
}
|
@ -10,7 +10,6 @@ use std::ptr;
|
||||
|
||||
use pango;
|
||||
use pango_sys;
|
||||
use glib_ffi;
|
||||
|
||||
use glib::translate::*;
|
||||
|
||||
@ -23,8 +22,7 @@ pub fn pango_itemize(
|
||||
cached_iter: Option<&mut AttrIterator>,
|
||||
) -> Vec<Item> {
|
||||
unsafe {
|
||||
//FromGlibPtrContainer::from_glib_full(pango_sys::pango_itemize(
|
||||
from_glib_full_as_vec(pango_sys::pango_itemize(
|
||||
FromGlibPtrContainer::from_glib_full(pango_sys::pango_itemize(
|
||||
context.to_glib_none().0,
|
||||
text.as_ptr() as *const i8,
|
||||
start_index as i32,
|
||||
@ -37,12 +35,6 @@ pub fn pango_itemize(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsafe fn from_glib_full_as_vec(ptr: *mut glib_ffi::GList) -> Vec<Item> {
|
||||
let num = glib_ffi::g_list_length(ptr) as usize;
|
||||
FromGlibContainer::from_glib_full_num(ptr, num)
|
||||
}
|
||||
|
||||
pub fn pango_shape(
|
||||
text: &str,
|
||||
offset: usize,
|
||||
|
@ -10,7 +10,7 @@ use glib::signal;
|
||||
|
||||
use pango;
|
||||
|
||||
use neovim_lib::NeovimApi;
|
||||
use neovim_lib::{NeovimApi, NeovimApiAsync};
|
||||
use neovim_lib::neovim_api::Tabpage;
|
||||
|
||||
use nvim;
|
||||
@ -39,6 +39,14 @@ impl State {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn close_tab(&self, idx: u32) {
|
||||
if let Some(mut nvim) = self.nvim.as_ref().unwrap().nvim() {
|
||||
nvim.command_async(&format!(":tabc {}", idx + 1))
|
||||
.cb(|r| r.report_err())
|
||||
.call();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Tabline {
|
||||
@ -55,6 +63,7 @@ impl Tabline {
|
||||
tabs.set_scrollable(true);
|
||||
tabs.set_show_border(false);
|
||||
tabs.set_border_width(0);
|
||||
tabs.set_hexpand(true);
|
||||
tabs.hide();
|
||||
|
||||
let state = Rc::new(RefCell::new(State::new()));
|
||||
@ -113,7 +122,33 @@ impl Tabline {
|
||||
let title = gtk::Label::new(None);
|
||||
title.set_ellipsize(pango::EllipsizeMode::Middle);
|
||||
title.set_width_chars(25);
|
||||
self.tabs.append_page(&empty, Some(&title));
|
||||
let close_btn = gtk::Button::new_from_icon_name(
|
||||
"window-close-symbolic",
|
||||
gtk::IconSize::Menu.into(),
|
||||
);
|
||||
close_btn.set_relief(gtk::ReliefStyle::None);
|
||||
close_btn.get_style_context().unwrap().add_class("small-button");
|
||||
close_btn.set_focus_on_click(false);
|
||||
let label_box = gtk::Box::new(gtk::Orientation::Horizontal, 0);
|
||||
label_box.pack_start(&title, true, false, 0);
|
||||
label_box.pack_start(&close_btn, false, false, 0);
|
||||
title.show();
|
||||
close_btn.show();
|
||||
self.tabs.append_page(&empty, Some(&label_box));
|
||||
|
||||
let tabs = self.tabs.clone();
|
||||
let state_ref = Rc::clone(&self.state);
|
||||
close_btn.connect_clicked(move |btn| {
|
||||
let current_label = btn
|
||||
.get_parent().unwrap();
|
||||
for i in 0..tabs.get_n_pages() {
|
||||
let page = tabs.get_nth_page(Some(i)).unwrap();
|
||||
let label = tabs.get_tab_label(&page).unwrap();
|
||||
if label == current_label {
|
||||
state_ref.borrow().close_tab(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if count > tabs.len() {
|
||||
for _ in tabs.len()..count {
|
||||
@ -126,6 +161,12 @@ impl Tabline {
|
||||
let tab_label = self.tabs
|
||||
.get_tab_label(&tab_child.unwrap())
|
||||
.unwrap()
|
||||
.downcast::<gtk::Box>()
|
||||
.unwrap()
|
||||
.get_children()
|
||||
.into_iter()
|
||||
.next()
|
||||
.unwrap()
|
||||
.downcast::<gtk::Label>()
|
||||
.unwrap();
|
||||
tab_label.set_text(tab.1.as_ref().unwrap_or(&"??".to_owned()));
|
||||
|
223
src/ui.rs
223
src/ui.rs
@ -1,13 +1,13 @@
|
||||
use std::cell::{Ref, RefCell, RefMut};
|
||||
use std::{env, thread};
|
||||
use std::path::Path;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use gdk;
|
||||
use gtk;
|
||||
use gtk_sys;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{AboutDialog, ApplicationWindow, HeaderBar, Image, SettingsExt, ToolButton};
|
||||
use gtk::{AboutDialog, ApplicationWindow, Button, HeaderBar, Orientation, Paned, SettingsExt};
|
||||
use gio::prelude::*;
|
||||
use gio::{Menu, MenuExt, MenuItem, SimpleAction};
|
||||
use toml;
|
||||
@ -17,6 +17,8 @@ use shell::{self, Shell, ShellOptions};
|
||||
use shell_dlg;
|
||||
use project::Projects;
|
||||
use plug_manager;
|
||||
use file_browser::FileBrowserWidget;
|
||||
use subscriptions::SubscriptionHandle;
|
||||
|
||||
macro_rules! clone {
|
||||
(@param _) => ( _ );
|
||||
@ -37,6 +39,7 @@ macro_rules! clone {
|
||||
|
||||
const DEFAULT_WIDTH: i32 = 800;
|
||||
const DEFAULT_HEIGHT: i32 = 600;
|
||||
const DEFAULT_SIDEBAR_WIDTH: i32 = 200;
|
||||
|
||||
pub struct Ui {
|
||||
initialized: bool,
|
||||
@ -45,21 +48,30 @@ pub struct Ui {
|
||||
shell: Rc<RefCell<Shell>>,
|
||||
projects: Rc<RefCell<Projects>>,
|
||||
plug_manager: Arc<UiMutex<plug_manager::Manager>>,
|
||||
file_browser: Arc<UiMutex<FileBrowserWidget>>,
|
||||
}
|
||||
|
||||
pub struct Components {
|
||||
window: Option<ApplicationWindow>,
|
||||
window_state: WindowState,
|
||||
open_btn: ToolButton,
|
||||
open_btn: Button,
|
||||
}
|
||||
|
||||
impl Components {
|
||||
fn new() -> Components {
|
||||
let save_image =
|
||||
Image::new_from_icon_name("document-open", gtk_sys::GTK_ICON_SIZE_SMALL_TOOLBAR as i32);
|
||||
|
||||
let open_btn = Button::new();
|
||||
let open_btn_box = gtk::Box::new(gtk::Orientation::Horizontal, 3);
|
||||
open_btn_box.pack_start(>k::Label::new("Open"), false, false, 3);
|
||||
open_btn_box.pack_start(
|
||||
>k::Image::new_from_icon_name("pan-down-symbolic", gtk::IconSize::Menu.into()),
|
||||
false,
|
||||
false,
|
||||
3,
|
||||
);
|
||||
open_btn.add(&open_btn_box);
|
||||
open_btn.set_can_focus(false);
|
||||
Components {
|
||||
open_btn: ToolButton::new(Some(&save_image), "Open"),
|
||||
open_btn,
|
||||
window: None,
|
||||
window_state: WindowState::load(),
|
||||
}
|
||||
@ -79,6 +91,7 @@ impl Ui {
|
||||
let plug_manager = plug_manager::Manager::new();
|
||||
|
||||
let plug_manager = Arc::new(UiMutex::new(plug_manager));
|
||||
let file_browser = Arc::new(UiMutex::new(FileBrowserWidget::new()));
|
||||
let comps = Arc::new(UiMutex::new(Components::new()));
|
||||
let settings = Rc::new(RefCell::new(Settings::new()));
|
||||
let shell = Rc::new(RefCell::new(Shell::new(settings.clone(), options)));
|
||||
@ -93,6 +106,7 @@ impl Ui {
|
||||
settings,
|
||||
projects,
|
||||
plug_manager,
|
||||
file_browser,
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,6 +120,7 @@ impl Ui {
|
||||
settings.init();
|
||||
|
||||
let window = ApplicationWindow::new(app);
|
||||
let main = Paned::new(Orientation::Horizontal);
|
||||
|
||||
{
|
||||
// initialize window from comps
|
||||
@ -126,48 +141,6 @@ impl Ui {
|
||||
}
|
||||
}
|
||||
|
||||
// Client side decorations including the toolbar are disabled via NVIM_GTK_NO_HEADERBAR=1
|
||||
let use_header_bar = env::var("NVIM_GTK_NO_HEADERBAR")
|
||||
.map(|opt| opt.trim() != "1")
|
||||
.unwrap_or(true);
|
||||
|
||||
if app.prefers_app_menu() || use_header_bar {
|
||||
self.create_main_menu(app, &window);
|
||||
}
|
||||
|
||||
if use_header_bar {
|
||||
let header_bar = HeaderBar::new();
|
||||
|
||||
let projects = self.projects.clone();
|
||||
header_bar.pack_start(&comps.open_btn);
|
||||
comps
|
||||
.open_btn
|
||||
.connect_clicked(move |_| projects.borrow_mut().show());
|
||||
|
||||
let save_image = Image::new_from_icon_name(
|
||||
"document-save",
|
||||
gtk_sys::GTK_ICON_SIZE_SMALL_TOOLBAR as i32,
|
||||
);
|
||||
let save_btn = ToolButton::new(Some(&save_image), "Save");
|
||||
|
||||
let shell = self.shell.clone();
|
||||
save_btn.connect_clicked(move |_| shell.borrow_mut().edit_save_all());
|
||||
header_bar.pack_start(&save_btn);
|
||||
|
||||
let paste_image = Image::new_from_icon_name(
|
||||
"edit-paste",
|
||||
gtk_sys::GTK_ICON_SIZE_SMALL_TOOLBAR as i32,
|
||||
);
|
||||
let paste_btn = ToolButton::new(Some(&paste_image), "Paste");
|
||||
let shell = self.shell.clone();
|
||||
paste_btn.connect_clicked(move |_| shell.borrow_mut().edit_paste());
|
||||
header_bar.pack_start(&paste_btn);
|
||||
|
||||
header_bar.set_show_close_button(true);
|
||||
|
||||
window.set_titlebar(Some(&header_bar));
|
||||
}
|
||||
|
||||
if restore_win_state {
|
||||
if comps.window_state.is_maximized {
|
||||
window.maximize();
|
||||
@ -177,15 +150,51 @@ impl Ui {
|
||||
comps.window_state.current_width,
|
||||
comps.window_state.current_height,
|
||||
);
|
||||
|
||||
main.set_position(comps.window_state.sidebar_width);
|
||||
} else {
|
||||
window.set_default_size(DEFAULT_WIDTH, DEFAULT_HEIGHT);
|
||||
main.set_position(DEFAULT_SIDEBAR_WIDTH);
|
||||
}
|
||||
}
|
||||
|
||||
// Client side decorations including the toolbar are disabled via NVIM_GTK_NO_HEADERBAR=1
|
||||
let use_header_bar = env::var("NVIM_GTK_NO_HEADERBAR")
|
||||
.map(|opt| opt.trim() != "1")
|
||||
.unwrap_or(true);
|
||||
|
||||
if app.prefers_app_menu() || use_header_bar {
|
||||
self.create_main_menu(app, &window);
|
||||
}
|
||||
|
||||
let update_subtitle = if use_header_bar {
|
||||
Some(self.create_header_bar())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let show_sidebar_action =
|
||||
SimpleAction::new_stateful("show-sidebar", None, &false.to_variant());
|
||||
let file_browser_ref = self.file_browser.clone();
|
||||
let comps_ref = self.comps.clone();
|
||||
window.connect_size_allocate(move |window, _| {
|
||||
gtk_window_size_allocate(window, &mut *comps_ref.borrow_mut())
|
||||
show_sidebar_action.connect_change_state(move |action, value| {
|
||||
if let Some(ref value) = *value {
|
||||
action.set_state(value);
|
||||
let is_active = value.get::<bool>().unwrap();
|
||||
file_browser_ref.borrow().set_visible(is_active);
|
||||
comps_ref.borrow_mut().window_state.show_sidebar = is_active;
|
||||
}
|
||||
});
|
||||
app.add_action(&show_sidebar_action);
|
||||
|
||||
let comps_ref = self.comps.clone();
|
||||
window.connect_size_allocate(clone!(main => move |window, _| {
|
||||
gtk_window_size_allocate(
|
||||
window,
|
||||
&mut *comps_ref.borrow_mut(),
|
||||
&main,
|
||||
);
|
||||
}));
|
||||
|
||||
let comps_ref = self.comps.clone();
|
||||
window.connect_window_state_event(move |_, event| {
|
||||
@ -199,10 +208,44 @@ impl Ui {
|
||||
});
|
||||
|
||||
let shell = self.shell.borrow();
|
||||
window.add(&**shell);
|
||||
let file_browser = self.file_browser.borrow();
|
||||
main.pack1(&**file_browser, false, false);
|
||||
main.pack2(&**shell, true, false);
|
||||
|
||||
window.add(&main);
|
||||
|
||||
window.show_all();
|
||||
window.set_title("NeovimGtk");
|
||||
|
||||
if restore_win_state {
|
||||
// Hide sidebar, if it wasn't shown last time.
|
||||
// Has to be done after show_all(), so it won't be shown again.
|
||||
let show_sidebar = self.comps.borrow().window_state.show_sidebar;
|
||||
show_sidebar_action.change_state(&show_sidebar.to_variant());
|
||||
}
|
||||
|
||||
let comps_ref = self.comps.clone();
|
||||
let update_title = shell.state.borrow().subscribe(
|
||||
"BufEnter,DirChanged",
|
||||
&["expand('%:p')", "getcwd()"],
|
||||
move |args| {
|
||||
let comps = comps_ref.borrow();
|
||||
let window = comps.window.as_ref().unwrap();
|
||||
let file_path = &args[0];
|
||||
let dir = Path::new(&args[1]);
|
||||
let filename = if file_path.is_empty() {
|
||||
"[No Name]"
|
||||
} else if let Some(rel_path) = Path::new(&file_path)
|
||||
.strip_prefix(&dir)
|
||||
.ok()
|
||||
.and_then(|p| p.to_str())
|
||||
{
|
||||
rel_path
|
||||
} else {
|
||||
&file_path
|
||||
};
|
||||
window.set_title(filename);
|
||||
},
|
||||
);
|
||||
|
||||
let comps_ref = self.comps.clone();
|
||||
let shell_ref = self.shell.clone();
|
||||
@ -220,14 +263,71 @@ impl Ui {
|
||||
}));
|
||||
|
||||
let state_ref = self.shell.borrow().state.clone();
|
||||
let file_browser_ref = self.file_browser.clone();
|
||||
let plug_manager_ref = self.plug_manager.clone();
|
||||
shell.set_nvim_started_cb(Some(move || {
|
||||
let state = state_ref.borrow();
|
||||
plug_manager_ref
|
||||
.borrow_mut()
|
||||
.init_nvim_client(state_ref.borrow().nvim_clone());
|
||||
file_browser_ref.borrow_mut().init(&state);
|
||||
state.set_autocmds();
|
||||
state.run_now(&update_title);
|
||||
if let Some(ref update_subtitle) = update_subtitle {
|
||||
state.run_now(&update_subtitle);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
fn create_header_bar(&self) -> SubscriptionHandle {
|
||||
let header_bar = HeaderBar::new();
|
||||
let comps = self.comps.borrow();
|
||||
let window = comps.window.as_ref().unwrap();
|
||||
|
||||
let projects = self.projects.clone();
|
||||
header_bar.pack_start(&comps.open_btn);
|
||||
comps
|
||||
.open_btn
|
||||
.connect_clicked(move |_| projects.borrow_mut().show());
|
||||
|
||||
let new_tab_btn =
|
||||
Button::new_from_icon_name("tab-new-symbolic", gtk::IconSize::SmallToolbar.into());
|
||||
let shell_ref = Rc::clone(&self.shell);
|
||||
new_tab_btn.connect_clicked(move |_| shell_ref.borrow_mut().new_tab());
|
||||
new_tab_btn.set_can_focus(false);
|
||||
new_tab_btn.set_tooltip_text("Open a new tab");
|
||||
header_bar.pack_start(&new_tab_btn);
|
||||
|
||||
let paste_btn =
|
||||
Button::new_from_icon_name("edit-paste-symbolic", gtk::IconSize::SmallToolbar.into());
|
||||
let shell = self.shell.clone();
|
||||
paste_btn.connect_clicked(move |_| shell.borrow_mut().edit_paste());
|
||||
paste_btn.set_can_focus(false);
|
||||
paste_btn.set_tooltip_text("Paste from clipboard");
|
||||
header_bar.pack_end(&paste_btn);
|
||||
|
||||
let save_btn = Button::new_with_label("Save All");
|
||||
let shell = self.shell.clone();
|
||||
save_btn.connect_clicked(move |_| shell.borrow_mut().edit_save_all());
|
||||
save_btn.set_can_focus(false);
|
||||
header_bar.pack_end(&save_btn);
|
||||
|
||||
header_bar.set_show_close_button(true);
|
||||
|
||||
window.set_titlebar(Some(&header_bar));
|
||||
|
||||
let shell = self.shell.borrow();
|
||||
let update_subtitle = shell.state.borrow().subscribe(
|
||||
"DirChanged",
|
||||
&["getcwd()"],
|
||||
move |args| {
|
||||
header_bar.set_subtitle(&*args[0]);
|
||||
},
|
||||
);
|
||||
|
||||
update_subtitle
|
||||
}
|
||||
|
||||
fn create_main_menu(&self, app: >k::Application, window: >k::ApplicationWindow) {
|
||||
let plug_manager = self.plug_manager.clone();
|
||||
|
||||
@ -237,6 +337,10 @@ impl Ui {
|
||||
section.append_item(&MenuItem::new("New Window", "app.new-window"));
|
||||
menu.append_section(None, §ion);
|
||||
|
||||
let section = Menu::new();
|
||||
section.append_item(&MenuItem::new("Sidebar", "app.show-sidebar"));
|
||||
menu.append_section(None, §ion);
|
||||
|
||||
let section = Menu::new();
|
||||
section.append_item(&MenuItem::new("Plugins", "app.Plugins"));
|
||||
section.append_item(&MenuItem::new("About", "app.HelpAbout"));
|
||||
@ -293,12 +397,19 @@ fn gtk_delete(comps: &UiMutex<Components>, shell: &RefCell<Shell>) -> Inhibit {
|
||||
})
|
||||
}
|
||||
|
||||
fn gtk_window_size_allocate(app_window: >k::ApplicationWindow, comps: &mut Components) {
|
||||
fn gtk_window_size_allocate(
|
||||
app_window: >k::ApplicationWindow,
|
||||
comps: &mut Components,
|
||||
main: &Paned,
|
||||
) {
|
||||
if !app_window.is_maximized() {
|
||||
let (current_width, current_height) = app_window.get_size();
|
||||
comps.window_state.current_width = current_width;
|
||||
comps.window_state.current_height = current_height;
|
||||
}
|
||||
if comps.window_state.show_sidebar {
|
||||
comps.window_state.sidebar_width = main.get_position();
|
||||
}
|
||||
}
|
||||
|
||||
fn gtk_window_state_event(event: &gdk::EventWindowState, comps: &mut Components) {
|
||||
@ -312,6 +423,8 @@ struct WindowState {
|
||||
current_width: i32,
|
||||
current_height: i32,
|
||||
is_maximized: bool,
|
||||
show_sidebar: bool,
|
||||
sidebar_width: i32,
|
||||
}
|
||||
|
||||
impl WindowState {
|
||||
@ -320,6 +433,8 @@ impl WindowState {
|
||||
current_width: DEFAULT_WIDTH,
|
||||
current_height: DEFAULT_HEIGHT,
|
||||
is_maximized: false,
|
||||
show_sidebar: false,
|
||||
sidebar_width: DEFAULT_SIDEBAR_WIDTH,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user