mirror of https://github.com/sgoudham/neovide.git
progress toward splitting main into bridge
parent
b3647d69c4
commit
35a675c8a4
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,27 @@
|
|||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use rmpv::Value;
|
||||||
|
use nvim_rs::{Neovim, Handler, compat::tokio::Compat};
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use tokio::process::ChildStdin;
|
||||||
|
|
||||||
|
use crate::error_handling::ResultPanicExplanation;
|
||||||
|
use crate::editor::Editor;
|
||||||
|
use super::events::parse_neovim_event;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct NeovimHandler(pub Arc<Mutex<Editor>>);
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Handler for NeovimHandler {
|
||||||
|
type Writer = Compat<ChildStdin>;
|
||||||
|
|
||||||
|
async fn handle_notify(&self, event_name: String, arguments: Vec<Value>, _neovim: Neovim<Compat<ChildStdin>>) {
|
||||||
|
let parsed_events = parse_neovim_event(event_name, arguments)
|
||||||
|
.unwrap_or_explained_panic("Could not parse event", "Could not parse event from neovim");
|
||||||
|
for event in parsed_events {
|
||||||
|
let mut editor = self.0.lock().unwrap();
|
||||||
|
editor.handle_redraw_event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,172 +1,172 @@
|
|||||||
use skulpin::winit::event::{KeyboardInput, ElementState, ModifiersState, VirtualKeyCode};
|
use skulpin::winit::event::{KeyboardInput, ElementState, ModifiersState, VirtualKeyCode};
|
||||||
|
|
||||||
fn parse_keycode(keycode: VirtualKeyCode) -> Option<(String, bool)> {
|
fn parse_keycode(keycode: VirtualKeyCode) -> Option<(String, bool)> {
|
||||||
match keycode {
|
match keycode {
|
||||||
VirtualKeyCode::Key1 => Some(("1".to_string(), false)),
|
VirtualKeyCode::Key1 => Some(("1".to_string(), false)),
|
||||||
VirtualKeyCode::Key2 => Some(("2".to_string(), false)),
|
VirtualKeyCode::Key2 => Some(("2".to_string(), false)),
|
||||||
VirtualKeyCode::Key3 => Some(("3".to_string(), false)),
|
VirtualKeyCode::Key3 => Some(("3".to_string(), false)),
|
||||||
VirtualKeyCode::Key4 => Some(("4".to_string(), false)),
|
VirtualKeyCode::Key4 => Some(("4".to_string(), false)),
|
||||||
VirtualKeyCode::Key5 => Some(("5".to_string(), false)),
|
VirtualKeyCode::Key5 => Some(("5".to_string(), false)),
|
||||||
VirtualKeyCode::Key6 => Some(("6".to_string(), false)),
|
VirtualKeyCode::Key6 => Some(("6".to_string(), false)),
|
||||||
VirtualKeyCode::Key7 => Some(("7".to_string(), false)),
|
VirtualKeyCode::Key7 => Some(("7".to_string(), false)),
|
||||||
VirtualKeyCode::Key8 => Some(("8".to_string(), false)),
|
VirtualKeyCode::Key8 => Some(("8".to_string(), false)),
|
||||||
VirtualKeyCode::Key9 => Some(("9".to_string(), false)),
|
VirtualKeyCode::Key9 => Some(("9".to_string(), false)),
|
||||||
VirtualKeyCode::Key0 => Some(("0".to_string(), false)),
|
VirtualKeyCode::Key0 => Some(("0".to_string(), false)),
|
||||||
VirtualKeyCode::A => Some(("a".to_string(), false)),
|
VirtualKeyCode::A => Some(("a".to_string(), false)),
|
||||||
VirtualKeyCode::B => Some(("b".to_string(), false)),
|
VirtualKeyCode::B => Some(("b".to_string(), false)),
|
||||||
VirtualKeyCode::C => Some(("c".to_string(), false)),
|
VirtualKeyCode::C => Some(("c".to_string(), false)),
|
||||||
VirtualKeyCode::D => Some(("d".to_string(), false)),
|
VirtualKeyCode::D => Some(("d".to_string(), false)),
|
||||||
VirtualKeyCode::E => Some(("e".to_string(), false)),
|
VirtualKeyCode::E => Some(("e".to_string(), false)),
|
||||||
VirtualKeyCode::F => Some(("f".to_string(), false)),
|
VirtualKeyCode::F => Some(("f".to_string(), false)),
|
||||||
VirtualKeyCode::G => Some(("g".to_string(), false)),
|
VirtualKeyCode::G => Some(("g".to_string(), false)),
|
||||||
VirtualKeyCode::H => Some(("h".to_string(), false)),
|
VirtualKeyCode::H => Some(("h".to_string(), false)),
|
||||||
VirtualKeyCode::I => Some(("i".to_string(), false)),
|
VirtualKeyCode::I => Some(("i".to_string(), false)),
|
||||||
VirtualKeyCode::J => Some(("j".to_string(), false)),
|
VirtualKeyCode::J => Some(("j".to_string(), false)),
|
||||||
VirtualKeyCode::K => Some(("k".to_string(), false)),
|
VirtualKeyCode::K => Some(("k".to_string(), false)),
|
||||||
VirtualKeyCode::L => Some(("l".to_string(), false)),
|
VirtualKeyCode::L => Some(("l".to_string(), false)),
|
||||||
VirtualKeyCode::M => Some(("m".to_string(), false)),
|
VirtualKeyCode::M => Some(("m".to_string(), false)),
|
||||||
VirtualKeyCode::N => Some(("n".to_string(), false)),
|
VirtualKeyCode::N => Some(("n".to_string(), false)),
|
||||||
VirtualKeyCode::O => Some(("o".to_string(), false)),
|
VirtualKeyCode::O => Some(("o".to_string(), false)),
|
||||||
VirtualKeyCode::P => Some(("p".to_string(), false)),
|
VirtualKeyCode::P => Some(("p".to_string(), false)),
|
||||||
VirtualKeyCode::Q => Some(("q".to_string(), false)),
|
VirtualKeyCode::Q => Some(("q".to_string(), false)),
|
||||||
VirtualKeyCode::R => Some(("r".to_string(), false)),
|
VirtualKeyCode::R => Some(("r".to_string(), false)),
|
||||||
VirtualKeyCode::S => Some(("s".to_string(), false)),
|
VirtualKeyCode::S => Some(("s".to_string(), false)),
|
||||||
VirtualKeyCode::T => Some(("t".to_string(), false)),
|
VirtualKeyCode::T => Some(("t".to_string(), false)),
|
||||||
VirtualKeyCode::U => Some(("u".to_string(), false)),
|
VirtualKeyCode::U => Some(("u".to_string(), false)),
|
||||||
VirtualKeyCode::V => Some(("v".to_string(), false)),
|
VirtualKeyCode::V => Some(("v".to_string(), false)),
|
||||||
VirtualKeyCode::W => Some(("w".to_string(), false)),
|
VirtualKeyCode::W => Some(("w".to_string(), false)),
|
||||||
VirtualKeyCode::X => Some(("x".to_string(), false)),
|
VirtualKeyCode::X => Some(("x".to_string(), false)),
|
||||||
VirtualKeyCode::Y => Some(("y".to_string(), false)),
|
VirtualKeyCode::Y => Some(("y".to_string(), false)),
|
||||||
VirtualKeyCode::Z => Some(("z".to_string(), false)),
|
VirtualKeyCode::Z => Some(("z".to_string(), false)),
|
||||||
VirtualKeyCode::Escape => Some(("ESC".to_string(), true)),
|
VirtualKeyCode::Escape => Some(("ESC".to_string(), true)),
|
||||||
VirtualKeyCode::F1 => Some(("F1".to_string(), true)),
|
VirtualKeyCode::F1 => Some(("F1".to_string(), true)),
|
||||||
VirtualKeyCode::F2 => Some(("F2".to_string(), true)),
|
VirtualKeyCode::F2 => Some(("F2".to_string(), true)),
|
||||||
VirtualKeyCode::F3 => Some(("F3".to_string(), true)),
|
VirtualKeyCode::F3 => Some(("F3".to_string(), true)),
|
||||||
VirtualKeyCode::F4 => Some(("F4".to_string(), true)),
|
VirtualKeyCode::F4 => Some(("F4".to_string(), true)),
|
||||||
VirtualKeyCode::F5 => Some(("F5".to_string(), true)),
|
VirtualKeyCode::F5 => Some(("F5".to_string(), true)),
|
||||||
VirtualKeyCode::F6 => Some(("F6".to_string(), true)),
|
VirtualKeyCode::F6 => Some(("F6".to_string(), true)),
|
||||||
VirtualKeyCode::F7 => Some(("F7".to_string(), true)),
|
VirtualKeyCode::F7 => Some(("F7".to_string(), true)),
|
||||||
VirtualKeyCode::F8 => Some(("F8".to_string(), true)),
|
VirtualKeyCode::F8 => Some(("F8".to_string(), true)),
|
||||||
VirtualKeyCode::F9 => Some(("F9".to_string(), true)),
|
VirtualKeyCode::F9 => Some(("F9".to_string(), true)),
|
||||||
VirtualKeyCode::F10 => Some(("F10".to_string(), true)),
|
VirtualKeyCode::F10 => Some(("F10".to_string(), true)),
|
||||||
VirtualKeyCode::F11 => Some(("F11".to_string(), true)),
|
VirtualKeyCode::F11 => Some(("F11".to_string(), true)),
|
||||||
VirtualKeyCode::F12 => Some(("F12".to_string(), true)),
|
VirtualKeyCode::F12 => Some(("F12".to_string(), true)),
|
||||||
VirtualKeyCode::F13 => Some(("F13".to_string(), true)),
|
VirtualKeyCode::F13 => Some(("F13".to_string(), true)),
|
||||||
VirtualKeyCode::F14 => Some(("F14".to_string(), true)),
|
VirtualKeyCode::F14 => Some(("F14".to_string(), true)),
|
||||||
VirtualKeyCode::F15 => Some(("F15".to_string(), true)),
|
VirtualKeyCode::F15 => Some(("F15".to_string(), true)),
|
||||||
VirtualKeyCode::F16 => Some(("F16".to_string(), true)),
|
VirtualKeyCode::F16 => Some(("F16".to_string(), true)),
|
||||||
VirtualKeyCode::F17 => Some(("F17".to_string(), true)),
|
VirtualKeyCode::F17 => Some(("F17".to_string(), true)),
|
||||||
VirtualKeyCode::F18 => Some(("F18".to_string(), true)),
|
VirtualKeyCode::F18 => Some(("F18".to_string(), true)),
|
||||||
VirtualKeyCode::F19 => Some(("F19".to_string(), true)),
|
VirtualKeyCode::F19 => Some(("F19".to_string(), true)),
|
||||||
VirtualKeyCode::F20 => Some(("F20".to_string(), true)),
|
VirtualKeyCode::F20 => Some(("F20".to_string(), true)),
|
||||||
VirtualKeyCode::F21 => Some(("F21".to_string(), true)),
|
VirtualKeyCode::F21 => Some(("F21".to_string(), true)),
|
||||||
VirtualKeyCode::F22 => Some(("F22".to_string(), true)),
|
VirtualKeyCode::F22 => Some(("F22".to_string(), true)),
|
||||||
VirtualKeyCode::F23 => Some(("F23".to_string(), true)),
|
VirtualKeyCode::F23 => Some(("F23".to_string(), true)),
|
||||||
VirtualKeyCode::F24 => Some(("F24".to_string(), true)),
|
VirtualKeyCode::F24 => Some(("F24".to_string(), true)),
|
||||||
VirtualKeyCode::Insert => Some(("Insert".to_string(), true)),
|
VirtualKeyCode::Insert => Some(("Insert".to_string(), true)),
|
||||||
VirtualKeyCode::Home => Some(("Home".to_string(), true)),
|
VirtualKeyCode::Home => Some(("Home".to_string(), true)),
|
||||||
VirtualKeyCode::Delete => Some(("Delete".to_string(), true)),
|
VirtualKeyCode::Delete => Some(("Delete".to_string(), true)),
|
||||||
VirtualKeyCode::End => Some(("End".to_string(), true)),
|
VirtualKeyCode::End => Some(("End".to_string(), true)),
|
||||||
VirtualKeyCode::PageDown => Some(("PageDown".to_string(), true)),
|
VirtualKeyCode::PageDown => Some(("PageDown".to_string(), true)),
|
||||||
VirtualKeyCode::PageUp => Some(("PageUp".to_string(), true)),
|
VirtualKeyCode::PageUp => Some(("PageUp".to_string(), true)),
|
||||||
VirtualKeyCode::Left => Some(("Left".to_string(), true)),
|
VirtualKeyCode::Left => Some(("Left".to_string(), true)),
|
||||||
VirtualKeyCode::Up => Some(("Up".to_string(), true)),
|
VirtualKeyCode::Up => Some(("Up".to_string(), true)),
|
||||||
VirtualKeyCode::Right => Some(("Right".to_string(), true)),
|
VirtualKeyCode::Right => Some(("Right".to_string(), true)),
|
||||||
VirtualKeyCode::Down => Some(("Down".to_string(), true)),
|
VirtualKeyCode::Down => Some(("Down".to_string(), true)),
|
||||||
VirtualKeyCode::Back => Some(("BS".to_string(), true)),
|
VirtualKeyCode::Back => Some(("BS".to_string(), true)),
|
||||||
VirtualKeyCode::Return => Some(("Enter".to_string(), true)),
|
VirtualKeyCode::Return => Some(("Enter".to_string(), true)),
|
||||||
VirtualKeyCode::Space => Some(("Space".to_string(), true)),
|
VirtualKeyCode::Space => Some(("Space".to_string(), true)),
|
||||||
VirtualKeyCode::Caret => Some(("^".to_string(), false)),
|
VirtualKeyCode::Caret => Some(("^".to_string(), false)),
|
||||||
VirtualKeyCode::Apostrophe => Some(("'".to_string(), false)),
|
VirtualKeyCode::Apostrophe => Some(("'".to_string(), false)),
|
||||||
VirtualKeyCode::Backslash => Some(("Bslash".to_string(), true)),
|
VirtualKeyCode::Backslash => Some(("Bslash".to_string(), true)),
|
||||||
VirtualKeyCode::Colon => Some((":".to_string(), false)),
|
VirtualKeyCode::Colon => Some((":".to_string(), false)),
|
||||||
VirtualKeyCode::Comma => Some((",".to_string(), false)),
|
VirtualKeyCode::Comma => Some((",".to_string(), false)),
|
||||||
VirtualKeyCode::Equals => Some(("=".to_string(), false)),
|
VirtualKeyCode::Equals => Some(("=".to_string(), false)),
|
||||||
VirtualKeyCode::Grave => Some(("`".to_string(), false)),
|
VirtualKeyCode::Grave => Some(("`".to_string(), false)),
|
||||||
VirtualKeyCode::LBracket => Some(("[".to_string(), false)),
|
VirtualKeyCode::LBracket => Some(("[".to_string(), false)),
|
||||||
VirtualKeyCode::Minus => Some(("-".to_string(), false)),
|
VirtualKeyCode::Minus => Some(("-".to_string(), false)),
|
||||||
VirtualKeyCode::Period => Some((".".to_string(), false)),
|
VirtualKeyCode::Period => Some((".".to_string(), false)),
|
||||||
VirtualKeyCode::RBracket => Some(("]".to_string(), false)),
|
VirtualKeyCode::RBracket => Some(("]".to_string(), false)),
|
||||||
VirtualKeyCode::Semicolon => Some((";".to_string(), false)),
|
VirtualKeyCode::Semicolon => Some((";".to_string(), false)),
|
||||||
VirtualKeyCode::Slash => Some(("/".to_string(), false)),
|
VirtualKeyCode::Slash => Some(("/".to_string(), false)),
|
||||||
VirtualKeyCode::Tab => Some(("Tab".to_string(), true)),
|
VirtualKeyCode::Tab => Some(("Tab".to_string(), true)),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_modifiers(modifiers: ModifiersState, keycode_text: String, special: bool) -> String {
|
fn append_modifiers(modifiers: ModifiersState, keycode_text: String, special: bool) -> String {
|
||||||
let mut result = keycode_text;
|
let mut result = keycode_text;
|
||||||
let mut special = special;
|
let mut special = special;
|
||||||
|
|
||||||
if modifiers.shift() {
|
if modifiers.shift() {
|
||||||
result = match result.as_ref() {
|
result = match result.as_ref() {
|
||||||
"1" => "!".to_string(),
|
"1" => "!".to_string(),
|
||||||
"2" => "@".to_string(),
|
"2" => "@".to_string(),
|
||||||
"3" => "#".to_string(),
|
"3" => "#".to_string(),
|
||||||
"4" => "$".to_string(),
|
"4" => "$".to_string(),
|
||||||
"5" => "%".to_string(),
|
"5" => "%".to_string(),
|
||||||
"6" => "^".to_string(),
|
"6" => "^".to_string(),
|
||||||
"7" => "&".to_string(),
|
"7" => "&".to_string(),
|
||||||
"8" => "*".to_string(),
|
"8" => "*".to_string(),
|
||||||
"9" => "(".to_string(),
|
"9" => "(".to_string(),
|
||||||
"0" => ")".to_string(),
|
"0" => ")".to_string(),
|
||||||
"'" => "\"".to_string(),
|
"'" => "\"".to_string(),
|
||||||
"Bslash" => {
|
"Bslash" => {
|
||||||
special = false;
|
special = false;
|
||||||
"|".to_string()
|
"|".to_string()
|
||||||
},
|
},
|
||||||
"," => {
|
"," => {
|
||||||
special = true;
|
special = true;
|
||||||
"lt".to_string()
|
"lt".to_string()
|
||||||
},
|
},
|
||||||
"=" => "+".to_string(),
|
"=" => "+".to_string(),
|
||||||
"`" => "~".to_string(),
|
"`" => "~".to_string(),
|
||||||
"[" => "{".to_string(),
|
"[" => "{".to_string(),
|
||||||
"-" => "_".to_string(),
|
"-" => "_".to_string(),
|
||||||
"." => ">".to_string(),
|
"." => ">".to_string(),
|
||||||
"]" => "}".to_string(),
|
"]" => "}".to_string(),
|
||||||
";" => ":".to_string(),
|
";" => ":".to_string(),
|
||||||
"/" => "?".to_string(),
|
"/" => "?".to_string(),
|
||||||
other => {
|
other => {
|
||||||
special = true;
|
special = true;
|
||||||
format!("S-{}", other)
|
format!("S-{}", other)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if modifiers.ctrl() {
|
if modifiers.ctrl() {
|
||||||
special = true;
|
special = true;
|
||||||
result = format!("C-{}", result);
|
result = format!("C-{}", result);
|
||||||
}
|
}
|
||||||
if modifiers.alt() {
|
if modifiers.alt() {
|
||||||
special = true;
|
special = true;
|
||||||
result = format!("M-{}", result);
|
result = format!("M-{}", result);
|
||||||
}
|
}
|
||||||
if modifiers.logo() {
|
if modifiers.logo() {
|
||||||
special = true;
|
special = true;
|
||||||
result = format!("D-{}", result);
|
result = format!("D-{}", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if special {
|
if special {
|
||||||
result = format!("<{}>", result);
|
result = format!("<{}>", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn construct_keybinding_string(input: KeyboardInput) -> Option<String> {
|
pub fn construct_keybinding_string(input: KeyboardInput) -> Option<String> {
|
||||||
match input {
|
match input {
|
||||||
KeyboardInput {
|
KeyboardInput {
|
||||||
state: ElementState::Pressed,
|
state: ElementState::Pressed,
|
||||||
virtual_keycode: Some(keycode),
|
virtual_keycode: Some(keycode),
|
||||||
modifiers,
|
modifiers,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
if let Some((keycode_text, special)) = parse_keycode(keycode) {
|
if let Some((keycode_text, special)) = parse_keycode(keycode) {
|
||||||
Some(append_modifiers(modifiers, keycode_text, special))
|
Some(append_modifiers(modifiers, keycode_text, special))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
mod events;
|
||||||
|
mod handler;
|
||||||
|
mod keybindings;
|
||||||
|
mod ui_commands;
|
||||||
|
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::process::Stdio;
|
||||||
|
|
||||||
|
use rmpv::Value;
|
||||||
|
use nvim_rs::{create::tokio as create, UiAttachOptions};
|
||||||
|
use tokio::runtime::Runtime;
|
||||||
|
use tokio::process::Command;
|
||||||
|
use tokio::sync::mpsc::UnboundedReceiver;
|
||||||
|
|
||||||
|
pub use events::*;
|
||||||
|
pub use keybindings::*;
|
||||||
|
pub use ui_commands::UiCommand;
|
||||||
|
use crate::editor::Editor;
|
||||||
|
use crate::error_handling::ResultPanicExplanation;
|
||||||
|
use handler::NeovimHandler;
|
||||||
|
|
||||||
|
#[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(std::env::args().skip(1))
|
||||||
|
.stderr(Stdio::inherit());
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
set_windows_creation_flags(&mut cmd);
|
||||||
|
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn start_process(editor: Arc<Mutex<Editor>>, mut receiver: UnboundedReceiver<UiCommand>, grid_dimensions: (u64, u64)) {
|
||||||
|
let (width, height) = grid_dimensions;
|
||||||
|
let (mut nvim, io_handler, _) = create::new_child_cmd(&mut create_nvim_command(), NeovimHandler(editor.clone())).await
|
||||||
|
.unwrap_or_explained_panic("Could not create nvim process", "Could not locate or start the neovim process");
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
match io_handler.await {
|
||||||
|
Err(join_error) => eprintln!("Error joining IO loop: '{}'", join_error),
|
||||||
|
Ok(Err(error)) => eprintln!("Error: '{}'", error),
|
||||||
|
Ok(Ok(())) => {}
|
||||||
|
};
|
||||||
|
std::process::exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
nvim.set_var("neovide", Value::Boolean(true)).await
|
||||||
|
.unwrap_or_explained_panic("Could not communicate.", "Could not communicate with neovim process");
|
||||||
|
let mut options = UiAttachOptions::new();
|
||||||
|
options.set_linegrid_external(true);
|
||||||
|
options.set_rgb(true);
|
||||||
|
nvim.ui_attach(width as i64, height as i64, &options).await
|
||||||
|
.unwrap_or_explained_panic("Could not attach.", "Could not attach ui to neovim process");
|
||||||
|
|
||||||
|
let nvim = Arc::new(nvim);
|
||||||
|
loop {
|
||||||
|
let mut commands = Vec::new();
|
||||||
|
let mut resize_command = None;
|
||||||
|
while let Ok(ui_command) = receiver.try_recv() {
|
||||||
|
if let UiCommand::Resize { .. } = ui_command {
|
||||||
|
resize_command = Some(ui_command);
|
||||||
|
} else {
|
||||||
|
commands.push(ui_command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(resize_command) = resize_command {
|
||||||
|
commands.push(resize_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ui_command in commands.into_iter() {
|
||||||
|
ui_command.execute(&nvim).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_nvim(editor: Arc<Mutex<Editor>>, receiver: UnboundedReceiver<UiCommand>, grid_dimensions: (u64, u64)) {
|
||||||
|
let rt = Runtime::new().unwrap();
|
||||||
|
|
||||||
|
rt.spawn(async move {
|
||||||
|
start_process(editor, receiver, grid_dimensions).await;
|
||||||
|
});
|
||||||
|
}
|
@ -1,37 +1,37 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use nvim_rs::Neovim;
|
use nvim_rs::Neovim;
|
||||||
use nvim_rs::compat::tokio::Compat;
|
use nvim_rs::compat::tokio::Compat;
|
||||||
use tokio::process::ChildStdin;
|
use tokio::process::ChildStdin;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum UiCommand {
|
pub enum UiCommand {
|
||||||
Resize { width: i64, height: i64 },
|
Resize { width: i64, height: i64 },
|
||||||
Keyboard(String),
|
Keyboard(String),
|
||||||
MouseButton { action: String, position: (i64, i64) },
|
MouseButton { action: String, position: (i64, i64) },
|
||||||
Scroll { direction: String, position: (i64, i64) },
|
Scroll { direction: String, position: (i64, i64) },
|
||||||
Drag(i64, i64)
|
Drag(i64, i64)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UiCommand {
|
impl UiCommand {
|
||||||
pub async fn execute(self, nvim: &Neovim<Compat<ChildStdin>>) {
|
pub async fn execute(self, nvim: &Neovim<Compat<ChildStdin>>) {
|
||||||
match self {
|
match self {
|
||||||
UiCommand::Resize { width, height } =>
|
UiCommand::Resize { width, height } =>
|
||||||
nvim.ui_try_resize(width.max(10), height.max(3)).await
|
nvim.ui_try_resize(width.max(10), height.max(3)).await
|
||||||
.expect("Resize failed"),
|
.expect("Resize failed"),
|
||||||
UiCommand::Keyboard(input_command) => {
|
UiCommand::Keyboard(input_command) => {
|
||||||
nvim.input(&input_command).await
|
nvim.input(&input_command).await
|
||||||
.expect("Input failed");
|
.expect("Input failed");
|
||||||
},
|
},
|
||||||
UiCommand::MouseButton { action, position: (grid_x, grid_y) } =>
|
UiCommand::MouseButton { action, position: (grid_x, grid_y) } =>
|
||||||
nvim.input_mouse("left", &action, "", 0, grid_x, grid_y).await
|
nvim.input_mouse("left", &action, "", 0, grid_x, grid_y).await
|
||||||
.expect("Mouse Input Failed"),
|
.expect("Mouse Input Failed"),
|
||||||
UiCommand::Scroll { direction, position: (grid_x, grid_y) } =>
|
UiCommand::Scroll { direction, position: (grid_x, grid_y) } =>
|
||||||
nvim.input_mouse("wheel", &direction, "", 0, grid_x, grid_y).await
|
nvim.input_mouse("wheel", &direction, "", 0, grid_x, grid_y).await
|
||||||
.expect("Mouse Scroll Failed"),
|
.expect("Mouse Scroll Failed"),
|
||||||
UiCommand::Drag(grid_x, grid_y) =>
|
UiCommand::Drag(grid_x, grid_y) =>
|
||||||
nvim.input_mouse("left", "drag", "", 0, grid_x, grid_y).await
|
nvim.input_mouse("left", "drag", "", 0, grid_x, grid_y).await
|
||||||
.expect("Mouse Drag Failed")
|
.expect("Mouse Drag Failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,122 +1,30 @@
|
|||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
|
mod bridge;
|
||||||
mod editor;
|
mod editor;
|
||||||
mod events;
|
|
||||||
mod window;
|
mod window;
|
||||||
mod keybindings;
|
|
||||||
mod renderer;
|
mod renderer;
|
||||||
mod error_handling;
|
mod error_handling;
|
||||||
mod ui_commands;
|
|
||||||
|
|
||||||
#[macro_use] extern crate derive_new;
|
#[macro_use] extern crate derive_new;
|
||||||
#[macro_use] extern crate rust_embed;
|
#[macro_use] extern crate rust_embed;
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::process::Stdio;
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use rmpv::Value;
|
|
||||||
use nvim_rs::{create::tokio as create, Neovim, UiAttachOptions, Handler, compat::tokio::Compat};
|
|
||||||
use tokio::process::{ChildStdin, Command};
|
|
||||||
use tokio::task::spawn_blocking;
|
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
use tokio::sync::mpsc::{unbounded_channel, UnboundedSender, UnboundedReceiver};
|
use tokio::sync::mpsc::unbounded_channel;
|
||||||
|
|
||||||
use window::ui_loop;
|
use window::ui_loop;
|
||||||
use editor::Editor;
|
use editor::Editor;
|
||||||
use events::parse_neovim_event;
|
use bridge::{start_nvim, UiCommand};
|
||||||
use error_handling::ResultPanicExplanation;
|
|
||||||
use ui_commands::UiCommand;
|
|
||||||
|
|
||||||
const INITIAL_WIDTH: u64 = 100;
|
const INITIAL_WIDTH: u64 = 100;
|
||||||
const INITIAL_HEIGHT: u64 = 50;
|
const INITIAL_HEIGHT: u64 = 50;
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
fn set_windows_creation_flags(cmd: &mut Command) {
|
|
||||||
use std::os::windows::process::CommandExt;
|
|
||||||
cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_nvim_command() -> Command {
|
|
||||||
let mut cmd = Command::new("nvim");
|
|
||||||
|
|
||||||
cmd.arg("--embed")
|
|
||||||
.args(std::env::args().skip(1))
|
|
||||||
.stderr(Stdio::inherit());
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
set_windows_creation_flags(&mut cmd);
|
|
||||||
|
|
||||||
cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct NeovimHandler(Arc<Mutex<Editor>>);
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl Handler for NeovimHandler {
|
|
||||||
type Writer = Compat<ChildStdin>;
|
|
||||||
|
|
||||||
async fn handle_notify(&self, event_name: String, arguments: Vec<Value>, _neovim: Neovim<Compat<ChildStdin>>) {
|
|
||||||
let parsed_events = parse_neovim_event(event_name, arguments)
|
|
||||||
.unwrap_or_explained_panic("Could not parse event", "Could not parse event from neovim");
|
|
||||||
for event in parsed_events {
|
|
||||||
let mut editor = self.0.lock().unwrap();
|
|
||||||
editor.handle_redraw_event(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn start_nvim(editor: Arc<Mutex<Editor>>, mut receiver: UnboundedReceiver<UiCommand>) {
|
|
||||||
let (mut nvim, io_handler, _) = create::new_child_cmd(&mut create_nvim_command(), NeovimHandler(editor.clone())).await
|
|
||||||
.unwrap_or_explained_panic("Could not create nvim process", "Could not locate or start the neovim process");
|
|
||||||
|
|
||||||
tokio::spawn(async move {
|
|
||||||
match io_handler.await {
|
|
||||||
Err(join_error) => eprintln!("Error joining IO loop: '{}'", join_error),
|
|
||||||
Ok(Err(error)) => eprintln!("Error: '{}'", error),
|
|
||||||
Ok(Ok(())) => {}
|
|
||||||
};
|
|
||||||
std::process::exit(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut options = UiAttachOptions::new();
|
|
||||||
options.set_linegrid_external(true);
|
|
||||||
options.set_rgb(true);
|
|
||||||
nvim.set_var("neovide", Value::Boolean(true)).await
|
|
||||||
.unwrap_or_explained_panic("Could not communicate.", "Could not communicate with neovim process");
|
|
||||||
nvim.ui_attach(INITIAL_WIDTH as i64, INITIAL_HEIGHT as i64, &options).await
|
|
||||||
.unwrap_or_explained_panic("Could not attach.", "Could not attach ui to neovim process");
|
|
||||||
|
|
||||||
let nvim = Arc::new(nvim);
|
|
||||||
loop {
|
|
||||||
let mut commands = Vec::new();
|
|
||||||
let mut resize_command = None;
|
|
||||||
while let Ok(ui_command) = receiver.try_recv() {
|
|
||||||
if let UiCommand::Resize { .. } = ui_command {
|
|
||||||
resize_command = Some(ui_command);
|
|
||||||
} else {
|
|
||||||
commands.push(ui_command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(resize_command) = resize_command {
|
|
||||||
commands.push(resize_command);
|
|
||||||
}
|
|
||||||
|
|
||||||
for ui_command in commands.into_iter() {
|
|
||||||
ui_command.execute(&nvim).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let rt = Runtime::new().unwrap();
|
|
||||||
|
|
||||||
let editor = Arc::new(Mutex::new(Editor::new(INITIAL_WIDTH, INITIAL_HEIGHT)));
|
let editor = Arc::new(Mutex::new(Editor::new(INITIAL_WIDTH, INITIAL_HEIGHT)));
|
||||||
let (sender, receiver) = unbounded_channel::<UiCommand>();
|
let (sender, receiver) = unbounded_channel::<UiCommand>();
|
||||||
let editor_clone = editor.clone();
|
let editor_clone = editor.clone();
|
||||||
rt.spawn(async move {
|
start_nvim(editor_clone, receiver, (INITIAL_WIDTH, INITIAL_HEIGHT));
|
||||||
start_nvim(editor_clone, receiver).await;
|
|
||||||
});
|
|
||||||
ui_loop(editor, sender, (INITIAL_WIDTH, INITIAL_HEIGHT));
|
ui_loop(editor, sender, (INITIAL_WIDTH, INITIAL_HEIGHT));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue