You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
neovide/src/bridge/mod.rs

169 lines
4.9 KiB
Rust

#[macro_use]
pub mod layouts;
mod events;
mod handler;
mod ui_commands;
use std::process::Stdio;
5 years ago
use std::sync::Arc;
5 years ago
use log::{error, info, trace};
use nvim_rs::{create::tokio as create, UiAttachOptions};
5 years ago
use rmpv::Value;
use tokio::process::Command;
5 years ago
use tokio::runtime::Runtime;
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
5 years ago
use crate::error_handling::ResultPanicExplanation;
use crate::settings::*;
use crate::INITIAL_DIMENSIONS;
pub use events::*;
5 years ago
use handler::NeovimHandler;
pub use layouts::*;
pub use ui_commands::UiCommand;
lazy_static! {
pub static ref BRIDGE: Bridge = Bridge::new();
}
#[cfg(target_os = "windows")]
fn set_windows_creation_flags(cmd: &mut Command) {
cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW
}
fn create_nvim_command() -> Command {
let mut cmd = Command::new("nvim");
cmd.arg("--embed")
.args(SETTINGS.neovim_arguments.iter().skip(1))
.stderr(Stdio::inherit());
#[cfg(target_os = "windows")]
set_windows_creation_flags(&mut cmd);
cmd
}
async fn drain(receiver: &mut UnboundedReceiver<UiCommand>) -> Option<Vec<UiCommand>> {
if let Some(ui_command) = receiver.recv().await {
let mut results = vec![ui_command];
while let Ok(ui_command) = receiver.try_recv() {
results.push(ui_command);
}
Some(results)
} else {
None
}
}
async fn start_process(mut receiver: UnboundedReceiver<UiCommand>) {
let (width, height) = INITIAL_DIMENSIONS;
5 years ago
let (mut nvim, io_handler, _) =
create::new_child_cmd(&mut create_nvim_command(), NeovimHandler())
.await
.unwrap_or_explained_panic("Could not locate or start the neovim process");
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);
}
5 years ago
}
Ok(Ok(())) => {}
};
std::process::exit(0);
});
5 years ago
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");
5 years ago
std::process::exit(0);
}
} else {
error!("Neovide requires version 0.4 or higher");
5 years ago
std::process::exit(0);
};
5 years ago
5 years ago
nvim.set_var("neovide", Value::Boolean(true))
.await
.unwrap_or_explained_panic("Could not communicate with neovim process");
let mut options = UiAttachOptions::new();
options.set_linegrid_external(true);
options.set_rgb(true);
5 years ago
nvim.ui_attach(width as i64, height as i64, &options)
.await
.unwrap_or_explained_panic("Could not attach ui to neovim process");
5 years ago
if let Err(command_error) = nvim.command("runtime! ginit.vim").await {
5 years ago
nvim.command(&format!(
"echomsg \"error encountered in ginit.vim {:?}\"",
command_error
))
.await
.ok();
5 years ago
}
info!("Neovim process attached");
let nvim = Arc::new(nvim);
let input_nvim = nvim.clone();
tokio::spawn(async move {
info!("UiCommand processor started");
while let Some(commands) = drain(&mut receiver).await {
let (resize_list, other_commands): (Vec<UiCommand>, Vec<UiCommand>) = commands
.into_iter()
.partition(|command| command.is_resize());
for command in resize_list
5 years ago
.into_iter()
.last()
.into_iter()
.chain(other_commands.into_iter())
{
let input_nvim = input_nvim.clone();
tokio::spawn(async move {
trace!("Executing UiCommand: {:?}", &command);
command.execute(&input_nvim).await;
});
}
}
});
5 years ago
SETTINGS.read_initial_values(&nvim).await;
SETTINGS.setup_changed_listeners(&nvim).await;
5 years ago
nvim.set_option("lazyredraw", Value::Boolean(false))
.await
.ok();
}
pub struct Bridge {
_runtime: Runtime, // Necessary to keep runtime running
5 years ago
sender: UnboundedSender<UiCommand>,
}
impl Bridge {
pub fn new() -> Bridge {
let runtime = Runtime::new().unwrap();
let (sender, receiver) = unbounded_channel::<UiCommand>();
runtime.spawn(async move {
start_process(receiver).await;
});
5 years ago
Bridge {
_runtime: runtime,
sender,
}
}
pub fn queue_command(&self, command: UiCommand) {
trace!("UiCommand queued: {:?}", &command);
5 years ago
self.sender.send(command).unwrap_or_explained_panic(
"Could not send UI command from the window system to the neovim process.",
);
}
}