diff --git a/src/bridge/events.rs b/src/bridge/events.rs index 926da29..84de51d 100644 --- a/src/bridge/events.rs +++ b/src/bridge/events.rs @@ -5,9 +5,7 @@ use std::fmt; use rmpv::Value; use skulpin::skia_safe::Color4f; -use crate::editor::EDITOR; use crate::editor::{Colors, CursorMode, CursorShape, Style}; -use crate::error_handling::ResultPanicExplanation; #[derive(Debug, Clone)] pub enum ParseError { @@ -610,7 +608,7 @@ fn parse_grid_destroy(grid_destroy_arguments: Vec) -> Result } fn parse_grid_cursor_goto(cursor_goto_arguments: Vec) -> Result { - let [grid_id, column, row] = + let [grid_id, row, column] = extract_values(cursor_goto_arguments, [Value::Nil, Value::Nil, Value::Nil])?; Ok(RedrawEvent::CursorGoto { @@ -1030,15 +1028,3 @@ pub fn parse_channel_list(channel_infos: Vec) -> Result> .map(parse_channel_info) .collect::>>() } - -pub(super) fn handle_redraw_event_group(arguments: Vec) { - 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 { - let mut editor = EDITOR.lock(); - editor.handle_redraw_event(parsed_event); - } - } -} diff --git a/src/bridge/handler.rs b/src/bridge/handler.rs index 892a2a9..f586a7c 100644 --- a/src/bridge/handler.rs +++ b/src/bridge/handler.rs @@ -1,17 +1,34 @@ +use std::sync::Arc; +use std::sync::mpsc::Sender; + use async_trait::async_trait; use log::trace; use nvim_rs::{compat::tokio::Compat, Handler, Neovim}; use rmpv::Value; +use tokio::sync::mpsc::UnboundedSender; use tokio::process::ChildStdin; use tokio::task; +use parking_lot::Mutex; -use super::events::handle_redraw_event_group; +use super::events::{parse_redraw_event, RedrawEvent}; use super::ui_commands::UiCommand; -use super::BRIDGE; use crate::settings::SETTINGS; +use crate::error_handling::ResultPanicExplanation; #[derive(Clone)] -pub struct NeovimHandler(); +pub struct NeovimHandler { + ui_command_sender: Arc>>, + redraw_event_sender: Arc>> +} + +impl NeovimHandler { + pub fn new(ui_command_sender: UnboundedSender, redraw_event_sender: Sender) -> NeovimHandler { + NeovimHandler { + ui_command_sender: Arc::new(Mutex::new(ui_command_sender)), + redraw_event_sender: Arc::new(Mutex::new(redraw_event_sender)) + } + } +} #[async_trait] impl Handler for NeovimHandler { @@ -24,20 +41,33 @@ impl Handler for NeovimHandler { _neovim: Neovim>, ) { trace!("Neovim notification: {:?}", &event_name); + + let ui_command_sender = self.ui_command_sender.clone(); + let redraw_event_sender = self.redraw_event_sender.clone(); task::spawn_blocking(move || match event_name.as_ref() { "redraw" => { - handle_redraw_event_group(arguments); + 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 { + let redraw_event_sender = redraw_event_sender.lock(); + redraw_event_sender.send(parsed_event).ok(); + } + } } "setting_changed" => { SETTINGS.handle_changed_notification(arguments); } #[cfg(windows)] "neovide.register_right_click" => { - BRIDGE.queue_command(UiCommand::RegisterRightClick); + let ui_command_sender = ui_command_sender.lock(); + ui_command_sender.send(UiCommand::RegisterRightClick).ok(); } #[cfg(windows)] "neovide.unregister_right_click" => { - BRIDGE.queue_command(UiCommand::UnregisterRightClick); + let ui_command_sender = ui_command_sender.lock(); + ui_command_sender.send(UiCommand::UnregisterRightClick).ok(); } _ => {} }) diff --git a/src/bridge/mod.rs b/src/bridge/mod.rs index 9cbfed3..02a5f4f 100644 --- a/src/bridge/mod.rs +++ b/src/bridge/mod.rs @@ -8,13 +8,17 @@ mod ui_commands; use std::process::Stdio; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; +use std::sync::mpsc::Sender; +use std::env; +use std::path::Path; +use std::thread; -use log::{error, info, trace, warn}; +use log::{error, info, warn}; 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 tokio::process::Command; +use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender}; use crate::error_handling::ResultPanicExplanation; use crate::settings::*; @@ -22,14 +26,8 @@ use crate::window::window_geometry_or_default; pub use events::*; use handler::NeovimHandler; pub use layouts::*; -use std::env; -use std::path::Path; pub use ui_commands::UiCommand; -lazy_static! { - pub static ref BRIDGE: Bridge = Bridge::new(); -} - #[cfg(windows)] fn set_windows_creation_flags(cmd: &mut Command) { cmd.creation_flags(0x0800_0000); // CREATE_NO_WINDOW @@ -112,25 +110,14 @@ pub fn create_nvim_command() -> Command { cmd } -async fn drain(receiver: &mut UnboundedReceiver) -> Option> { - 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) { +async fn start_process(ui_command_sender: UnboundedSender, mut ui_command_receiver: UnboundedReceiver, redraw_event_sender: Sender, running: Arc) { let (width, height) = window_geometry_or_default(); let (mut nvim, io_handler, _) = - create::new_child_cmd(&mut create_nvim_command(), NeovimHandler()) + create::new_child_cmd(&mut create_nvim_command(), NeovimHandler::new(ui_command_sender, redraw_event_sender)) .await .unwrap_or_explained_panic("Could not locate or start the neovim process"); + let close_watcher_running = running.clone(); tokio::spawn(async move { info!("Close watcher started"); match io_handler.await { @@ -142,7 +129,7 @@ async fn start_process(mut receiver: UnboundedReceiver) { } Ok(Ok(())) => {} }; - BRIDGE.running.store(false, Ordering::Relaxed); + close_watcher_running.store(false, Ordering::Relaxed); }); if let Ok(Value::Integer(correct_version)) = nvim.eval("has(\"nvim-0.4\")").await { @@ -233,31 +220,16 @@ async fn start_process(mut receiver: UnboundedReceiver) { let nvim = Arc::new(nvim); let input_nvim = nvim.clone(); + + let ui_command_processor_running = running.clone(); tokio::spawn(async move { info!("UiCommand processor started"); - while let Some(commands) = drain(&mut receiver).await { - if !BRIDGE.running.load(Ordering::Relaxed) { + while let Some(ui_command) = ui_command_receiver.recv().await { + if !ui_command_processor_running.load(Ordering::Relaxed) { return; } - let (resize_list, other_commands): (Vec, Vec) = commands - .into_iter() - .partition(|command| command.is_resize()); - - for command in resize_list - .into_iter() - .last() - .into_iter() - .chain(other_commands.into_iter()) - { - let input_nvim = input_nvim.clone(); - tokio::spawn(async move { - if !BRIDGE.running.load(Ordering::Relaxed) { - return; - } - trace!("Executing UiCommand: {:?}", &command); - command.execute(&input_nvim).await; - }); - } + + ui_command.execute(&input_nvim).await; } }); @@ -269,34 +241,16 @@ async fn start_process(mut receiver: UnboundedReceiver) { .ok(); } -pub struct Bridge { - _runtime: Runtime, // Necessary to keep runtime running - sender: UnboundedSender, - pub running: AtomicBool, -} - -impl Bridge { - pub fn new() -> Bridge { +pub fn start_bridge(ui_command_sender: UnboundedSender, ui_command_receiver: UnboundedReceiver, redraw_event_sender: Sender, running: Arc) { + thread::spawn(move || { let runtime = Runtime::new().unwrap(); - let (sender, receiver) = unbounded_channel::(); + let running_clone = running.clone(); runtime.spawn(async move { - start_process(receiver).await; + start_process(ui_command_sender, ui_command_receiver, redraw_event_sender, running_clone).await; }); - Bridge { - _runtime: runtime, - sender, - running: AtomicBool::new(true), - } - } - pub fn queue_command(&self, command: UiCommand) { - if !BRIDGE.running.load(Ordering::Relaxed) { - return; + while running.load(Ordering::Relaxed) { } - trace!("UiCommand queued: {:?}", &command); - self.sender.send(command).unwrap_or_explained_panic( - "Could not send UI command from the window system to the neovim process.", - ); - } + }); } diff --git a/src/bridge/ui_commands.rs b/src/bridge/ui_commands.rs index 65c5bd9..539a8b5 100644 --- a/src/bridge/ui_commands.rs +++ b/src/bridge/ui_commands.rs @@ -3,7 +3,6 @@ use nvim_rs::compat::tokio::Compat; use nvim_rs::Neovim; use tokio::process::ChildStdin; -use crate::editor::EDITOR; #[cfg(windows)] use crate::settings::windows_registry::{ register_rightclick_directory, register_rightclick_file, unregister_rightclick, @@ -56,32 +55,26 @@ impl UiCommand { grid_id, position: (grid_x, grid_y), } => { - if EDITOR.lock().mouse_enabled { - nvim.input_mouse("left", &action, "", grid_id as i64, grid_y as i64, grid_x as i64) - .await - .expect("Mouse Input Failed"); - } + nvim.input_mouse("left", &action, "", grid_id as i64, grid_y as i64, grid_x as i64) + .await + .expect("Mouse Input Failed"); } UiCommand::Scroll { direction, grid_id, position: (grid_x, grid_y), } => { - if EDITOR.lock().mouse_enabled { - nvim.input_mouse("wheel", &direction, "", grid_id as i64, grid_y as i64, grid_x as i64) - .await - .expect("Mouse Scroll Failed"); - } + nvim.input_mouse("wheel", &direction, "", grid_id as i64, grid_y as i64, grid_x as i64) + .await + .expect("Mouse Scroll Failed"); } UiCommand::Drag { grid_id, position: (grid_x, grid_y) } => { - if EDITOR.lock().mouse_enabled { - nvim.input_mouse("left", "drag", "", grid_id as i64, grid_y as i64, grid_x as i64) - .await - .expect("Mouse Drag Failed"); - } + nvim.input_mouse("left", "drag", "", grid_id as i64, grid_y as i64, grid_x as i64) + .await + .expect("Mouse Drag Failed"); } UiCommand::FocusLost => nvim .command("if exists('#FocusLost') | doautocmd FocusLost | endif") diff --git a/src/editor/mod.rs b/src/editor/mod.rs index d4bc66f..07e734e 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -3,12 +3,12 @@ mod grid; mod style; mod window; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::sync::Arc; +use std::sync::mpsc::{Sender, Receiver}; +use std::thread; use log::{error, trace}; -use parking_lot::Mutex; -use skulpin::skia_safe::colors; use crate::bridge::{EditorMode, GuiOption, RedrawEvent, WindowAnchor}; use crate::redraw_scheduler::REDRAW_SCHEDULER; @@ -17,107 +17,121 @@ pub use grid::CharacterGrid; pub use style::{Colors, Style}; pub use window::*; -lazy_static! { - pub static ref EDITOR: Arc> = Arc::new(Mutex::new(Editor::new())); +pub struct AnchorInfo { + pub anchor_grid_id: u64, + pub anchor_type: WindowAnchor, + pub anchor_left: f64, + pub anchor_top: f64, } -pub struct RenderInfo { - pub windows: Vec, - pub closed_window_ids: Vec, +impl WindowAnchor { + fn modified_top_left(&self, grid_left: f64, grid_top: f64, width: u64, height: u64) -> (f64, f64) { + match self { + WindowAnchor::NorthWest => ( + grid_left, + grid_top, + ), + WindowAnchor::NorthEast => ( + grid_left - width as f64, + grid_top, + ), + WindowAnchor::SouthWest => ( + grid_left, + grid_top - height as f64, + ), + WindowAnchor::SouthEast => ( + grid_left - width as f64, + grid_top - height as f64, + ), + } + } } -pub struct WindowRenderInfo { - pub grid_id: u64, - pub grid_position: (f64, f64), - pub width: u64, - pub height: u64, - pub floating: bool, - pub draw_commands: Vec +pub enum DrawCommand { + CloseWindow(u64), + Window { + grid_id: u64, + command: WindowDrawCommand + }, + UpdateCursor(Cursor), + FontChanged(String), + DefaultStyleChanged(Style), + TitleChanged(String), + SetMouseEnabled(bool), } pub struct Editor { - pub title: String, pub windows: HashMap, - pub closed_window_ids: HashSet, - pub mouse_enabled: bool, - pub guifont: Option, pub cursor: Cursor, - pub default_style: Arc