diff --git a/Cargo.lock b/Cargo.lock index ff218db..7a79c40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,6 +106,17 @@ dependencies = [ "raw-window-metal", ] +[[package]] +name = "async-trait" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3a45e77e34375a7923b1e8febb049bb011f064714a8e17a1a616fef01da13d" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.7", + "syn 1.0.54", +] + [[package]] name = "atty" version = "0.2.14" @@ -188,6 +199,22 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +[[package]] +name = "bytes" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" +dependencies = [ + "byteorder", + "iovec", +] + +[[package]] +name = "bytes" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" + [[package]] name = "calloop" version = "0.4.4" @@ -447,6 +474,30 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "crossbeam" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" +dependencies = [ + "cfg-if 0.1.10", + "crossbeam-channel 0.4.4", + "crossbeam-deque 0.7.3", + "crossbeam-epoch 0.8.2", + "crossbeam-queue", + "crossbeam-utils 0.7.2", +] + +[[package]] +name = "crossbeam-channel" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" +dependencies = [ + "crossbeam-utils 0.7.2", + "maybe-uninit", +] + [[package]] name = "crossbeam-channel" version = "0.5.0" @@ -454,7 +505,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils", + "crossbeam-utils 0.8.1", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" +dependencies = [ + "crossbeam-epoch 0.8.2", + "crossbeam-utils 0.7.2", + "maybe-uninit", ] [[package]] @@ -464,8 +526,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" dependencies = [ "cfg-if 1.0.0", - "crossbeam-epoch", - "crossbeam-utils", + "crossbeam-epoch 0.9.1", + "crossbeam-utils 0.8.1", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +dependencies = [ + "autocfg 1.0.1", + "cfg-if 0.1.10", + "crossbeam-utils 0.7.2", + "lazy_static", + "maybe-uninit", + "memoffset 0.5.6", + "scopeguard", ] [[package]] @@ -476,12 +553,34 @@ checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d" dependencies = [ "cfg-if 1.0.0", "const_fn", - "crossbeam-utils", + "crossbeam-utils 0.8.1", "lazy_static", - "memoffset", + "memoffset 0.6.1", "scopeguard", ] +[[package]] +name = "crossbeam-queue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" +dependencies = [ + "cfg-if 0.1.10", + "crossbeam-utils 0.7.2", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg 1.0.1", + "cfg-if 0.1.10", + "lazy_static", +] + [[package]] name = "crossbeam-utils" version = "0.8.1" @@ -493,6 +592,17 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crossfire" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8434f61eb40fc72030b18a370f7a06b428d27de66b0281977967216312b14dc7" +dependencies = [ + "async-trait", + "crossbeam", + "futures 0.3.8", +] + [[package]] name = "crunchy" version = "0.2.2" @@ -725,6 +835,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e" +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "font-kit" version = "0.10.0" @@ -808,6 +924,109 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +[[package]] +name = "futures" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7e4c2612746b0df8fed4ce0c69156021b704c9aefa360311c04e6e9e002eed" + +[[package]] +name = "futures" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b3b0c040a1fe6529d30b3c5944b280c7f0dcb2930d2c3062bca967b602583d0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b7109687aa4e177ef6fe84553af6280ef2778bdb7783ba44c9dc3399110fe64" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "847ce131b72ffb13b6109a221da9ad97a64cbe48feb1028356b836b47b8f1748" + +[[package]] +name = "futures-executor" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4caa2b2b68b880003057c1dd49f1ed937e38f22fcf6c212188a121f08cf40a65" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "611834ce18aaa1bd13c4b374f5d653e1027cf99b6b502584ff8c9a64413b30bb" + +[[package]] +name = "futures-macro" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77408a692f1f97bcc61dc001d752e00643408fbc922e4d634c655df50d595556" +dependencies = [ + "proc-macro-hack", + "proc-macro2 1.0.24", + "quote 1.0.7", + "syn 1.0.54", +] + +[[package]] +name = "futures-sink" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f878195a49cee50e006b02b93cf7e0a95a38ac7b776b4c4d9cc1207cd20fcb3d" + +[[package]] +name = "futures-task" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c554eb5bf48b2426c4771ab68c6b14468b6e76cc90996f528c3338d761a4d0d" +dependencies = [ + "once_cell", +] + +[[package]] +name = "futures-util" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d304cff4a7b99cfb7986f7d43fbe93d175e72e704a8860787cc95e9ffd85cbd2" +dependencies = [ + "futures 0.1.30", + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project 1.0.2", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", + "tokio-io", +] + [[package]] name = "getrandom" version = "0.1.15" @@ -1105,6 +1324,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "memoffset" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" +dependencies = [ + "autocfg 1.0.1", +] + [[package]] name = "memoffset" version = "0.6.1" @@ -1137,7 +1365,7 @@ dependencies = [ "kernel32-sys", "libc", "log", - "miow", + "miow 0.2.2", "net2", "slab", "winapi 0.2.8", @@ -1155,6 +1383,29 @@ dependencies = [ "slab", ] +[[package]] +name = "mio-named-pipes" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" +dependencies = [ + "log", + "mio", + "miow 0.3.6", + "winapi 0.3.9", +] + +[[package]] +name = "mio-uds" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" +dependencies = [ + "iovec", + "libc", + "mio", +] + [[package]] name = "miow" version = "0.2.2" @@ -1167,6 +1418,16 @@ dependencies = [ "ws2_32-sys", ] +[[package]] +name = "miow" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" +dependencies = [ + "socket2", + "winapi 0.3.9", +] + [[package]] name = "mockall" version = "0.7.2" @@ -1230,8 +1491,10 @@ name = "neovide" version = "0.6.0" dependencies = [ "anyhow", + "async-trait", "cargo-husky", "cfg-if 0.1.10", + "crossfire", "derive-new", "dirs", "euclid", @@ -1242,7 +1505,7 @@ dependencies = [ "log", "lru", "mockall", - "neovim-lib", + "nvim-rs", "parking_lot", "rand", "rmpv", @@ -1251,22 +1514,13 @@ dependencies = [ "skia-safe", "skribo", "skulpin", + "tokio", "unicode-segmentation", "which 4.0.2", "winapi 0.3.9", "winres", ] -[[package]] -name = "neovim-lib" -version = "0.6.0" -source = "git+https://github.com/kethku/neovim-lib#3a89df15c788fd0a3b28e5e15c25da88e5cdda2d" -dependencies = [ - "log", - "rmpv", - "unix_socket", -] - [[package]] name = "net2" version = "0.2.37" @@ -1391,6 +1645,20 @@ dependencies = [ "syn 1.0.54", ] +[[package]] +name = "nvim-rs" +version = "0.1.1-alpha.0" +source = "git+https://github.com/kethku/nvim-rs#109feea9e345fcbb2674384b0d6914ba4b8fc61e" +dependencies = [ + "async-trait", + "futures 0.3.8", + "log", + "pin-project 0.4.27", + "rmp", + "rmpv", + "tokio", +] + [[package]] name = "objc" version = "0.2.7" @@ -1400,6 +1668,12 @@ dependencies = [ "malloc_buf", ] +[[package]] +name = "once_cell" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" + [[package]] name = "openssl-probe" version = "0.1.2" @@ -1483,6 +1757,58 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +[[package]] +name = "pin-project" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15" +dependencies = [ + "pin-project-internal 0.4.27", +] + +[[package]] +name = "pin-project" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ccc2237c2c489783abd8c4c80e5450fc0e98644555b1364da68cc29aa151ca7" +dependencies = [ + "pin-project-internal 1.0.2", +] + +[[package]] +name = "pin-project-internal" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.7", + "syn 1.0.54", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8e8d2bf0b23038a4424865103a4df472855692821aab4e4f5c3312d461d9e5f" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.7", + "syn 1.0.54", +] + +[[package]] +name = "pin-project-lite" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "pkg-config" version = "0.3.19" @@ -1551,6 +1877,12 @@ version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" +[[package]] +name = "proc-macro-nested" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" + [[package]] name = "proc-macro2" version = "0.4.30" @@ -1662,7 +1994,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" dependencies = [ "autocfg 1.0.1", - "crossbeam-deque", + "crossbeam-deque 0.8.0", "either", "rayon-core", ] @@ -1673,9 +2005,9 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", + "crossbeam-channel 0.5.0", + "crossbeam-deque 0.8.0", + "crossbeam-utils 0.8.1", "lazy_static", "num_cpus", ] @@ -1733,8 +2065,6 @@ checksum = "601e306fb529fadf3faa482684fba756e1b93897864ef2ab2080b12775c04235" dependencies = [ "num-traits", "rmp", - "serde", - "serde_bytes", ] [[package]] @@ -1746,7 +2076,7 @@ dependencies = [ "base64", "blake2b_simd", "constant_time_eq", - "crossbeam-utils", + "crossbeam-utils 0.8.1", ] [[package]] @@ -1902,15 +2232,6 @@ version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" -[[package]] -name = "serde_bytes" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" -dependencies = [ - "serde", -] - [[package]] name = "serde_json" version = "1.0.60" @@ -1949,6 +2270,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" +[[package]] +name = "signal-hook-registry" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" +dependencies = [ + "libc", +] + [[package]] name = "skia-bindings" version = "0.32.1" @@ -2229,6 +2559,51 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +[[package]] +name = "tokio" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099837d3464c16a808060bb3f02263b412f6fafcb5d01c533d309985fbeebe48" +dependencies = [ + "bytes 0.5.6", + "fnv", + "iovec", + "lazy_static", + "libc", + "memchr", + "mio", + "mio-named-pipes", + "mio-uds", + "num_cpus", + "pin-project-lite", + "signal-hook-registry", + "slab", + "tokio-macros", + "winapi 0.3.9", +] + +[[package]] +name = "tokio-io" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" +dependencies = [ + "bytes 0.4.12", + "futures 0.1.30", + "log", +] + +[[package]] +name = "tokio-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e44da00bfc73a25f814cd8d7e57a68a5c31b74b3152a0a1d1f590c97ed06265a" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.7", + "syn 1.0.54", +] + [[package]] name = "toml" version = "0.5.7" @@ -2288,16 +2663,6 @@ dependencies = [ "regex", ] -[[package]] -name = "unix_socket" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aa2700417c405c38f5e6902d699345241c28c0b7ade4abaad71e35a87eb1564" -dependencies = [ - "cfg-if 0.1.10", - "libc", -] - [[package]] name = "vcpkg" version = "0.2.11" diff --git a/Cargo.toml b/Cargo.toml index 51c2bb5..35b614d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,10 @@ derive-new = "0.5" rmpv = "0.4.4" rust-embed = { version = "5.2.0", features = ["debug-embed"] } image = "0.22.3" -neovim-lib = { git = "https://github.com/kethku/neovim-lib" } +nvim-rs = { git = "https://github.com/kethku/nvim-rs", features = [ "use_tokio" ] } +tokio = { version = "0.2.9", features = [ "blocking", "process", "time" ] } +async-trait = "0.1.18" +crossfire = "0.1" lazy_static = "1.4.0" unicode-segmentation = "1.6.0" log = "0.4.8" diff --git a/src/bridge/handler.rs b/src/bridge/handler.rs index f586a7c..c330d28 100644 --- a/src/bridge/handler.rs +++ b/src/bridge/handler.rs @@ -2,6 +2,7 @@ use std::sync::Arc; use std::sync::mpsc::Sender; use async_trait::async_trait; +use crossfire::mpsc::TxUnbounded; use log::trace; use nvim_rs::{compat::tokio::Compat, Handler, Neovim}; use rmpv::Value; @@ -17,12 +18,12 @@ use crate::error_handling::ResultPanicExplanation; #[derive(Clone)] pub struct NeovimHandler { - ui_command_sender: Arc>>, - redraw_event_sender: Arc>> + ui_command_sender: Arc>>, + redraw_event_sender: Arc>> } impl NeovimHandler { - pub fn new(ui_command_sender: UnboundedSender, redraw_event_sender: Sender) -> NeovimHandler { + pub fn new(ui_command_sender: TxUnbounded, redraw_event_sender: TxUnbounded) -> NeovimHandler { NeovimHandler { ui_command_sender: Arc::new(Mutex::new(ui_command_sender)), redraw_event_sender: Arc::new(Mutex::new(redraw_event_sender)) diff --git a/src/bridge/mod.rs b/src/bridge/mod.rs index 38cad12..61c221f 100644 --- a/src/bridge/mod.rs +++ b/src/bridge/mod.rs @@ -3,10 +3,11 @@ pub mod layouts; mod events; mod ui_commands; +mod handler; use std::env; use std::path::Path; -use std::process::{Command, Stdio}; +use std::process::Stdio; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::{Receiver, Sender}; use std::sync::Arc; @@ -15,14 +16,19 @@ use std::thread; #[cfg(windows)] use std::os::windows::process::CommandExt; +use crossfire::mpsc::{TxUnbounded, RxUnbounded}; use log::{error, info, warn}; -use neovim_lib::{Neovim, NeovimApi, Session, UiAttachOptions}; +use nvim_rs::{create::tokio as create, UiAttachOptions}; use rmpv::Value; +use tokio::process::Command; +use tokio::runtime::Runtime; +use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; use crate::error_handling::ResultPanicExplanation; use crate::settings::*; use crate::window::window_geometry_or_default; pub use events::*; +use handler::NeovimHandler; pub use layouts::*; pub use ui_commands::UiCommand; @@ -108,157 +114,173 @@ pub fn create_nvim_command() -> Command { cmd } -pub fn start_bridge( - ui_command_sender: Sender, - ui_command_receiver: Receiver, - redraw_event_sender: Sender, +async fn start_neovim_runtime( + ui_command_sender: TxUnbounded, + ui_command_receiver: RxUnbounded, + redraw_event_sender: TxUnbounded, running: Arc, ) { - thread::spawn(move || { - let (width, height) = window_geometry_or_default(); - let mut session = Session::new_child_cmd(&mut create_nvim_command()) + let (width, height) = window_geometry_or_default(); + let handler = NeovimHandler::new(ui_command_sender.clone(), redraw_event_sender.clone()); + let (mut nvim, io_handler, _) = + create::new_child_cmd(&mut create_nvim_command(), handler) + .await .unwrap_or_explained_panic("Could not locate or start neovim process"); - let notification_receiver = session.start_event_loop_channel(); - let mut nvim = Neovim::new(session); + if nvim.get_api_info().await.is_err() { + error!("Cannot get neovim api info, either neovide is launched with an unknown command line option or neovim version not supported!"); + std::process::exit(-1); + } - if let Ok(Value::Integer(correct_version)) = nvim.eval("has(\"nvim-0.4\")") { - if correct_version.as_i64() != Some(1) { - error!("Neovide requires version 0.4 or higher"); - std::process::exit(0); + let close_watcher_running = running.clone(); + tokio::spawn(async move { + info!("Close watcher started"); + match io_handler.await { + Err(join_error) => error!("Error joining IO loop: '{}'", join_error), + Ok(Err(error)) => { + if !error.is_channel_closed() { + error!("Error: '{}'", error); + } } - } else { - error!("Neovide requires version 0.4 or higher"); - std::process::exit(0); + Ok(Ok(())) => {} }; + close_watcher_running.store(false, Ordering::Relaxed); + }); - nvim.set_var("neovide", Value::Boolean(true)) - .unwrap_or_explained_panic("Could not communicate with neovim process"); - if let Err(command_error) = nvim.command("runtime! ginit.vim") { - nvim.command(&format!( - "echomsg \"error encountered in ginit.vim {:?}\"", - command_error - )) - .ok(); + if let Ok(Value::Integer(correct_version)) = nvim.eval("has(\"nvim-0.4\")").await { + if correct_version.as_i64() != Some(1) { + error!("Neovide requires version 0.4 or higher"); + std::process::exit(0); } + } else { + error!("Neovide requires version 0.4 or higher"); + std::process::exit(0); + }; + + nvim.set_var("neovide", Value::Boolean(true)) + .await + .unwrap_or_explained_panic("Could not communicate with neovim process"); - nvim.set_client_info( - "neovide", - vec![ - (Value::from("major"), Value::from(0u64)), - (Value::from("minor"), Value::from(6u64)), - ], - "ui", - vec![], - vec![], - ) + if let Err(command_error) = nvim.command("runtime! ginit.vim").await { + nvim.command(&format!( + "echomsg \"error encountered in ginit.vim {:?}\"", + command_error + )) + .await .ok(); + } - let neovide_channel: u64 = nvim - .list_chans() - .ok() - .and_then(|channel_values| parse_channel_list(channel_values).ok()) - .and_then(|channel_list| { - channel_list.iter().find_map(|channel| match channel { - ChannelInfo { - id, - client: Some(ClientInfo { name, .. }), - .. - } if name == "neovide" => Some(*id), - _ => None, - }) + nvim.set_client_info( + "neovide", + vec![ + (Value::from("major"), Value::from(0u64)), + (Value::from("minor"), Value::from(6u64)), + ], + "ui", + vec![], + vec![], + ) + .await + .ok(); + + let neovide_channel: u64 = nvim + .list_chans() + .await + .ok() + .and_then(|channel_values| parse_channel_list(channel_values).ok()) + .and_then(|channel_list| { + channel_list.iter().find_map(|channel| match channel { + ChannelInfo { + id, + client: Some(ClientInfo { name, .. }), + .. + } if name == "neovide" => Some(*id), + _ => None, }) - .unwrap_or(0); + }) + .unwrap_or(0); - info!( - "Neovide registered to nvim with channel id {}", - neovide_channel - ); + info!( + "Neovide registered to nvim with channel id {}", + neovide_channel + ); - #[cfg(windows)] - nvim.command(&build_neovide_command( - neovide_channel, - 0, - "NeovideRegisterRightClick", - "register_right_click", - )) - .ok(); + #[cfg(windows)] + nvim.command(&build_neovide_command( + neovide_channel, + 0, + "NeovideRegisterRightClick", + "register_right_click", + )) + .await + .ok(); - #[cfg(windows)] - nvim.command(&build_neovide_command( - neovide_channel, - 0, - "NeovideUnregisterRightClick", - "unregister_right_click", - )) + #[cfg(windows)] + nvim.command(&build_neovide_command( + neovide_channel, + 0, + "NeovideUnregisterRightClick", + "unregister_right_click", + )) + .await + .ok(); + + nvim.set_option("lazyredraw", Value::Boolean(false)) + .await .ok(); - NeovimApi::set_option(&mut nvim, "lazyredraw", Value::Boolean(false)).ok(); - - let mut options = UiAttachOptions::new(); - options.set_linegrid_external(true); - options.set_multigrid_external(true); - options.set_rgb(true); - nvim.ui_attach(width as i64, height as i64, &options) - .unwrap_or_explained_panic("Could not attach ui to neovim process"); - info!("Neovim process attached"); + let mut options = UiAttachOptions::new(); + options.set_linegrid_external(true); + options.set_multigrid_external(true); + options.set_rgb(true); + nvim.ui_attach(width as i64, height as i64, &options) + .await + .unwrap_or_explained_panic("Could not attach ui to neovim process"); - let notification_running = running.clone(); - thread::spawn(move || loop { - if !notification_running.load(Ordering::Relaxed) { - break; - } - - match notification_receiver.recv() { - Ok((event_name, arguments)) => match event_name.as_ref() { - "redraw" => { - for events in arguments { - let parsed_events = parse_redraw_event(events) - .unwrap_or_explained_panic("Could not parse event from neovim"); - - for parsed_event in parsed_events { - redraw_event_sender.send(parsed_event).ok(); - } - } - } - "setting_changed" => { - SETTINGS.handle_changed_notification(arguments); - } - #[cfg(windows)] - "neovide.register_right_click" => { - ui_command_sender.send(UiCommand::RegisterRightClick).ok(); - } - #[cfg(windows)] - "neovide.unregister_right_click" => { - ui_command_sender.send(UiCommand::UnregisterRightClick).ok(); - } - _ => {} - }, - Err(_) => { - notification_running.store(false, Ordering::Relaxed); - break; - } - } - }); + info!("Neovim process attached"); - SETTINGS.read_initial_values(&mut nvim); - SETTINGS.setup_changed_listeners(&mut nvim); + let nvim = Arc::new(nvim); - let ui_command_running = running.clone(); - thread::spawn(move || loop { + let ui_command_running = running.clone(); + let input_nvim = nvim.clone(); + tokio::spawn(async move { + loop { if !ui_command_running.load(Ordering::Relaxed) { break; } - match ui_command_receiver.recv() { + match ui_command_receiver.recv().await { Ok(ui_command) => { - ui_command.execute(&mut nvim); + let input_nvim = input_nvim.clone(); + tokio::spawn(async move { + ui_command.execute(&input_nvim).await; + }); } Err(_) => { ui_command_running.store(false, Ordering::Relaxed); break; } } - }); + } }); + + SETTINGS.read_initial_values(&nvim).await; + SETTINGS.setup_changed_listeners(&nvim).await; +} + +pub struct Bridge { + _runtime: Runtime, // Necessary to keep runtime running +} + +pub fn start_bridge( + ui_command_sender: TxUnbounded, + ui_command_receiver: RxUnbounded, + redraw_event_sender: TxUnbounded, + running: Arc +) -> Bridge { + let runtime = Runtime::new().unwrap(); + runtime.spawn(start_neovim_runtime(ui_command_sender, ui_command_receiver, redraw_event_sender, running)); + Bridge { + _runtime: runtime + } } diff --git a/src/bridge/ui_commands.rs b/src/bridge/ui_commands.rs index fbbf894..06c14a5 100644 --- a/src/bridge/ui_commands.rs +++ b/src/bridge/ui_commands.rs @@ -1,5 +1,7 @@ use log::{error, trace}; -use neovim_lib::{Neovim, NeovimApi}; +use nvim_rs::compat::tokio::Compat; +use nvim_rs::Neovim; +use tokio::process::ChildStdin; #[cfg(windows)] use crate::settings::windows_registry::{ @@ -37,14 +39,15 @@ pub enum UiCommand { } impl UiCommand { - pub fn execute(self, nvim: &mut Neovim) { + pub async fn execute(self, nvim: &Neovim>) { match self { UiCommand::Resize { width, height } => nvim .ui_try_resize(width.max(10) as i64, height.max(3) as i64) + .await .expect("Resize failed"), UiCommand::Keyboard(input_command) => { trace!("Keyboard Input Sent: {}", input_command); - nvim.input(&input_command).expect("Input failed"); + nvim.input(&input_command).await.expect("Input failed"); } UiCommand::MouseButton { action, @@ -59,6 +62,7 @@ impl UiCommand { grid_y as i64, grid_x as i64, ) + .await .expect("Mouse Input Failed"); } UiCommand::Scroll { @@ -74,6 +78,7 @@ impl UiCommand { grid_y as i64, grid_x as i64, ) + .await .expect("Mouse Scroll Failed"); } UiCommand::Drag { @@ -88,32 +93,35 @@ impl UiCommand { grid_y as i64, grid_x as i64, ) + .await .expect("Mouse Drag Failed"); } UiCommand::FocusLost => nvim .command("if exists('#FocusLost') | doautocmd FocusLost | endif") + .await .expect("Focus Lost Failed"), UiCommand::FocusGained => nvim .command("if exists('#FocusGained') | doautocmd FocusGained | endif") + .await .expect("Focus Gained Failed"), UiCommand::FileDrop(path) => { - nvim.command(format!("e {}", path).as_str()).ok(); + nvim.command(format!("e {}", path).as_str()).await.ok(); } #[cfg(windows)] UiCommand::RegisterRightClick => { if unregister_rightclick() { let msg = "Could not unregister previous menu item. Possibly already registered or not running as Admin?"; - nvim.err_writeln(msg).ok(); + nvim.err_writeln(msg).await.ok(); error!("{}", msg); } if !register_rightclick_directory() { let msg = "Could not register directory context menu item. Possibly already registered or not running as Admin?"; - nvim.err_writeln(msg).ok(); + nvim.err_writeln(msg).await.ok(); error!("{}", msg); } if !register_rightclick_file() { let msg = "Could not register file context menu item. Possibly already registered or not running as Admin?"; - nvim.err_writeln(msg).ok(); + nvim.err_writeln(msg).await.ok(); error!("{}", msg); } } @@ -121,7 +129,7 @@ impl UiCommand { UiCommand::UnregisterRightClick => { if !unregister_rightclick() { let msg = "Could not remove context menu items. Possibly already removed or not running as Admin?"; - nvim.err_writeln(msg).ok(); + nvim.err_writeln(msg).await.ok(); error!("{}", msg); } } diff --git a/src/editor/mod.rs b/src/editor/mod.rs index db3094b..a5df711 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -10,6 +10,7 @@ use std::sync::mpsc::{Receiver, Sender}; use std::sync::Arc; use std::thread; +use crossfire::mpsc::RxUnbounded; use log::{error, trace, warn}; use crate::bridge::{EditorMode, GuiOption, RedrawEvent, WindowAnchor}; @@ -418,14 +419,14 @@ impl Editor { } pub fn start_editor( - redraw_event_receiver: Receiver, + redraw_event_receiver: RxUnbounded, batched_draw_command_sender: Sender>, window_command_sender: Sender, ) { thread::spawn(move || { let mut editor = Editor::new(batched_draw_command_sender, window_command_sender); - while let Ok(redraw_event) = redraw_event_receiver.recv() { + while let Ok(redraw_event) = redraw_event_receiver.recv_blocking() { editor.handle_redraw_event(redraw_event); } }); diff --git a/src/main.rs b/src/main.rs index d38f7c5..62d5fb4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,9 +18,11 @@ extern crate rust_embed; extern crate lazy_static; use std::process; +use std::sync::Arc; use std::sync::atomic::AtomicBool; use std::sync::mpsc::channel; -use std::sync::Arc; + +use crossfire::mpsc::unbounded_future; use window::window_geometry; @@ -130,12 +132,13 @@ fn main() { let running = Arc::new(AtomicBool::new(true)); - let (redraw_event_sender, redraw_event_receiver) = channel(); + let (redraw_event_sender, redraw_event_receiver) = unbounded_future(); let (batched_draw_command_sender, batched_draw_command_receiver) = channel(); - let (ui_command_sender, ui_command_receiver) = channel(); + let (ui_command_sender, ui_command_receiver) = unbounded_future(); let (window_command_sender, window_command_receiver) = channel(); - start_bridge( + // We need to keep the bridge reference around to prevent the tokio runtime from getting freed + let bridge = start_bridge( ui_command_sender.clone(), ui_command_receiver, redraw_event_sender, diff --git a/src/settings/mod.rs b/src/settings/mod.rs index 12214c2..26a3942 100644 --- a/src/settings/mod.rs +++ b/src/settings/mod.rs @@ -4,12 +4,14 @@ use std::convert::TryInto; #[cfg(not(test))] use flexi_logger::{Cleanup, Criterion, Duplicate, Logger, Naming}; +mod from_value; +pub use from_value::FromValue; use log::warn; -use neovim_lib::{Neovim, NeovimApi}; +use nvim_rs::compat::tokio::Compat; +use nvim_rs::Neovim; use parking_lot::RwLock; pub use rmpv::Value; -mod from_value; -pub use from_value::FromValue; +use tokio::process::ChildStdin; pub mod windows_registry; use crate::error_handling::ResultPanicExplanation; @@ -138,25 +140,25 @@ impl Settings { (*value).clone() } - pub fn read_initial_values(&self, nvim: &mut Neovim) { + pub async fn read_initial_values(&self, nvim: &Neovim>) { let keys: Vec = self.listeners.read().keys().cloned().collect(); for name in keys { let variable_name = format!("neovide_{}", name.to_string()); - match nvim.get_var(&variable_name) { + match nvim.get_var(&variable_name).await { Ok(value) => { self.listeners.read().get(&name).unwrap()(value); } Err(error) => { warn!("Initial value load failed for {}: {}", name, error); let setting = self.readers.read().get(&name).unwrap()(); - nvim.set_var(&variable_name, setting).ok(); + nvim.set_var(&variable_name, setting).await.ok(); } } } } - pub fn setup_changed_listeners(&self, nvim: &mut Neovim) { + pub async fn setup_changed_listeners(&self, nvim: &Neovim>) { let keys: Vec = self.listeners.read().keys().cloned().collect(); for name in keys { @@ -170,10 +172,12 @@ impl Settings { ), name ); - nvim.command(&vimscript).unwrap_or_explained_panic(&format!( - "Could not setup setting notifier for {}", - name - )); + nvim.command(&vimscript) + .await + .unwrap_or_explained_panic(&format!( + "Could not setup setting notifier for {}", + name + )); } } diff --git a/src/window/mod.rs b/src/window/mod.rs index 3a7a4aa..1df0c9d 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -6,6 +6,7 @@ use std::sync::atomic::AtomicBool; use std::sync::mpsc::{Receiver, Sender}; use std::sync::Arc; +use crossfire::mpsc::TxUnbounded; use skulpin::LogicalSize; use crate::bridge::UiCommand; @@ -72,7 +73,7 @@ fn windows_fix_dpi() { fn handle_new_grid_size( new_size: LogicalSize, renderer: &Renderer, - ui_command_sender: &Sender, + ui_command_sender: &TxUnbounded, ) { if new_size.width > 0 && new_size.height > 0 { // Add 1 here to make sure resizing doesn't change the grid size on startup @@ -90,7 +91,7 @@ fn handle_new_grid_size( pub fn create_window( batched_draw_command_receiver: Receiver>, window_command_receiver: Receiver, - ui_command_sender: Sender, + ui_command_sender: TxUnbounded, running: Arc, ) { let (width, height) = window_geometry_or_default(); diff --git a/src/window/sdl2/mod.rs b/src/window/sdl2/mod.rs index f3d54f3..e3419a3 100644 --- a/src/window/sdl2/mod.rs +++ b/src/window/sdl2/mod.rs @@ -1,9 +1,10 @@ use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::mpsc::{Receiver, Sender}; +use std::sync::mpsc::Receiver; use std::sync::Arc; use std::thread::sleep; use std::time::{Duration, Instant}; +use crossfire::mpsc::TxUnbounded; use log::{debug, error, trace}; use skulpin::ash::prelude::VkResult; use skulpin::sdl2; @@ -46,7 +47,7 @@ pub struct Sdl2WindowWrapper { fullscreen: bool, cached_size: (u32, u32), cached_position: (i32, i32), - ui_command_sender: Sender, + ui_command_sender: TxUnbounded, window_command_receiver: Receiver, running: Arc, } @@ -376,7 +377,7 @@ impl Sdl2WindowWrapper { pub fn start_loop( window_command_receiver: Receiver, - ui_command_sender: Sender, + ui_command_sender: TxUnbounded, running: Arc, logical_size: LogicalSize, renderer: Renderer,