diff --git a/src/bridge/events.rs b/src/bridge/events.rs index 84de51d..3979be1 100644 --- a/src/bridge/events.rs +++ b/src/bridge/events.rs @@ -700,7 +700,7 @@ fn parse_win_external_pos(win_external_pos_arguments: Vec) -> Result Command { cmd } -pub fn start_bridge(ui_command_sender: Sender, ui_command_receiver: Receiver, redraw_event_sender: Sender, running: Arc) { +pub fn start_bridge( + ui_command_sender: Sender, + ui_command_receiver: Receiver, + redraw_event_sender: Sender, + running: Arc, +) { thread::spawn(move || { let (width, height) = window_geometry_or_default(); - let mut session = Session::new_child_cmd(&mut create_nvim_command()).unwrap_or_explained_panic("Could not locate or start neovim process"); + let mut session = Session::new_child_cmd(&mut create_nvim_command()) + .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); @@ -126,7 +132,8 @@ pub fn start_bridge(ui_command_sender: Sender, ui_command_receiver: R std::process::exit(0); }; - nvim.set_var("neovide", Value::Boolean(true)).unwrap_or_explained_panic("Could not communicate with neovim process"); + 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 {:?}\"", @@ -200,61 +207,58 @@ pub fn start_bridge(ui_command_sender: Sender, ui_command_receiver: R SETTINGS.setup_changed_listeners(&mut nvim); let notification_running = running.clone(); - thread::spawn(move || { - loop { - if !notification_running.load(Ordering::Relaxed) { - break; - } + 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(); + 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(); } - _ => {} - }, - Err(error) => { - notification_running.store(false, Ordering::Relaxed); - break; + } } + "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(error) => { + error!("Notification channel closed: {}", error); + notification_running.store(false, Ordering::Relaxed); + break; } - } + } }); let ui_command_running = running.clone(); - thread::spawn(move || { - loop { - if !ui_command_running.load(Ordering::Relaxed) { - break; - } + thread::spawn(move || loop { + if !ui_command_running.load(Ordering::Relaxed) { + break; + } - match ui_command_receiver.recv() { - Ok(ui_command) => { - ui_command.execute(&mut nvim); - }, - Err(error) => { - ui_command_running.store(false, Ordering::Relaxed); - break; - } + match ui_command_receiver.recv() { + Ok(ui_command) => { + ui_command.execute(&mut nvim); + } + Err(error) => { + error!("Ui command channel closed: {}", error); + ui_command_running.store(false, Ordering::Relaxed); + break; } } }); diff --git a/src/bridge/ui_commands.rs b/src/bridge/ui_commands.rs index 8c0259c..1f5b43e 100644 --- a/src/bridge/ui_commands.rs +++ b/src/bridge/ui_commands.rs @@ -52,23 +52,44 @@ impl UiCommand { grid_id, position: (grid_x, grid_y), } => { - nvim.input_mouse("left", &action, "", grid_id as i64, grid_y as i64, grid_x as i64) - .expect("Mouse Input Failed"); + nvim.input_mouse( + "left", + &action, + "", + grid_id as i64, + grid_y as i64, + grid_x as i64, + ) + .expect("Mouse Input Failed"); } UiCommand::Scroll { direction, grid_id, position: (grid_x, grid_y), } => { - nvim.input_mouse("wheel", &direction, "", grid_id as i64, grid_y as i64, grid_x as i64) - .expect("Mouse Scroll Failed"); + nvim.input_mouse( + "wheel", + &direction, + "", + grid_id as i64, + grid_y as i64, + grid_x as i64, + ) + .expect("Mouse Scroll Failed"); } UiCommand::Drag { grid_id, - position: (grid_x, grid_y) + position: (grid_x, grid_y), } => { - nvim.input_mouse("left", "drag", "", grid_id as i64, grid_y as i64, grid_x as i64) - .expect("Mouse Drag Failed"); + nvim.input_mouse( + "left", + "drag", + "", + grid_id as i64, + grid_y as i64, + grid_x as i64, + ) + .expect("Mouse Drag Failed"); } UiCommand::FocusLost => nvim .command("if exists('#FocusLost') | doautocmd FocusLost | endif") diff --git a/src/editor/draw_command_batcher.rs b/src/editor/draw_command_batcher.rs new file mode 100644 index 0000000..8fef22e --- /dev/null +++ b/src/editor/draw_command_batcher.rs @@ -0,0 +1,31 @@ +use std::sync::mpsc::{channel, Receiver, SendError, Sender}; + +use super::DrawCommand; + +pub struct DrawCommandBatcher { + window_draw_command_sender: Sender, + window_draw_command_receiver: Receiver, + + batched_draw_command_sender: Sender>, +} + +impl DrawCommandBatcher { + pub fn new(batched_draw_command_sender: Sender>) -> DrawCommandBatcher { + let (sender, receiver) = channel(); + + DrawCommandBatcher { + window_draw_command_sender: sender, + window_draw_command_receiver: receiver, + batched_draw_command_sender, + } + } + + pub fn queue(&self, draw_command: DrawCommand) -> Result<(), SendError> { + self.window_draw_command_sender.send(draw_command) + } + + pub fn send_batch(&self) -> Result<(), SendError>> { + let batch = self.window_draw_command_receiver.try_iter().collect(); + self.batched_draw_command_sender.send(batch) + } +} diff --git a/src/editor/grid.rs b/src/editor/grid.rs index cc284ea..8c7fef1 100644 --- a/src/editor/grid.rs +++ b/src/editor/grid.rs @@ -71,7 +71,10 @@ impl CharacterGrid { pub fn row(&self, row_index: u64) -> Option<&[GridCell]> { if row_index < self.height { - Some(&self.characters[(row_index * self.width) as usize..((row_index + 1) * self.width) as usize]) + Some( + &self.characters + [(row_index * self.width) as usize..((row_index + 1) * self.width) as usize], + ) } else { None } @@ -230,7 +233,6 @@ mod tests { (thread_rng().gen::() % 500) + 1, (thread_rng().gen::() % 500) + 1, ); - let new_area = (width * height) as usize; let grid_cell = Some(( "foo".to_string(), @@ -243,6 +245,18 @@ mod tests { assert_eq!(character_grid.width, width); assert_eq!(character_grid.height, height); - assert_eq!(character_grid.characters, vec![grid_cell.clone(); new_area]); + + let (original_width, original_height) = context.size; + for x in 0..original_width.min(width) { + for y in 0..original_height.min(height) { + assert_eq!(character_grid.get_cell(x, y).unwrap(), &grid_cell); + } + } + + for x in original_width..width { + for y in original_height..height { + assert_eq!(character_grid.get_cell(x, y).unwrap(), &None); + } + } } } diff --git a/src/editor/mod.rs b/src/editor/mod.rs index 6b146dd..4452fd2 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -1,19 +1,21 @@ mod cursor; +mod draw_command_batcher; mod grid; mod style; mod window; use std::collections::HashMap; +use std::fmt; +use std::sync::mpsc::{Receiver, Sender}; use std::sync::Arc; -use std::sync::mpsc::{Sender, Receiver}; use std::thread; -use std::fmt; -use log::{error, warn, trace}; +use log::{error, trace, warn}; use crate::bridge::{EditorMode, GuiOption, RedrawEvent, WindowAnchor}; use crate::redraw_scheduler::REDRAW_SCHEDULER; pub use cursor::{Cursor, CursorMode, CursorShape}; +pub use draw_command_batcher::DrawCommandBatcher; pub use grid::CharacterGrid; pub use style::{Colors, Style}; pub use window::*; @@ -26,24 +28,18 @@ pub struct AnchorInfo { } impl WindowAnchor { - fn modified_top_left(&self, grid_left: f64, grid_top: f64, width: u64, height: u64) -> (f64, f64) { + 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, - ), + 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), } } } @@ -52,7 +48,7 @@ pub enum DrawCommand { CloseWindow(u64), Window { grid_id: u64, - command: WindowDrawCommand + command: WindowDrawCommand, }, UpdateCursor(Cursor), FontChanged(String), @@ -68,7 +64,9 @@ impl fmt::Debug for DrawCommand { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { match self { DrawCommand::CloseWindow(_) => write!(formatter, "CloseWindow"), - DrawCommand::Window { grid_id, command } => write!(formatter, "Window {} {:?}", grid_id, command), + DrawCommand::Window { grid_id, command } => { + write!(formatter, "Window {} {:?}", grid_id, command) + } DrawCommand::UpdateCursor(_) => write!(formatter, "UpdateCursor"), DrawCommand::FontChanged(_) => write!(formatter, "FontChanged"), DrawCommand::DefaultStyleChanged(_) => write!(formatter, "DefaultStyleChanged"), @@ -82,28 +80,33 @@ pub struct Editor { pub defined_styles: HashMap>, pub mode_list: Vec, pub current_mode: EditorMode, - pub draw_command_sender: Sender, + pub draw_command_batcher: Arc, pub window_command_sender: Sender, } impl Editor { - pub fn new(draw_command_sender: Sender, window_command_sender: Sender) -> Editor { + pub fn new( + batched_draw_command_sender: Sender>, + window_command_sender: Sender, + ) -> Editor { Editor { windows: HashMap::new(), cursor: Cursor::new(), defined_styles: HashMap::new(), mode_list: Vec::new(), current_mode: EditorMode::Unknown(String::from("")), - draw_command_sender, - window_command_sender + draw_command_batcher: Arc::new(DrawCommandBatcher::new(batched_draw_command_sender)), + window_command_sender, } } pub fn handle_redraw_event(&mut self, event: RedrawEvent) { match event { RedrawEvent::SetTitle { title } => { - self.window_command_sender.send(WindowCommand::TitleChanged(title)).ok(); - }, + self.window_command_sender + .send(WindowCommand::TitleChanged(title)) + .ok(); + } RedrawEvent::ModeInfoSet { cursor_modes } => self.mode_list = cursor_modes, RedrawEvent::OptionSet { gui_option } => self.set_option(gui_option), RedrawEvent::ModeChange { mode, mode_index } => { @@ -113,10 +116,14 @@ impl Editor { } } RedrawEvent::MouseOn => { - self.window_command_sender.send(WindowCommand::SetMouseEnabled(true)).ok(); + self.window_command_sender + .send(WindowCommand::SetMouseEnabled(true)) + .ok(); } RedrawEvent::MouseOff => { - self.window_command_sender.send(WindowCommand::SetMouseEnabled(false)).ok(); + self.window_command_sender + .send(WindowCommand::SetMouseEnabled(false)) + .ok(); } RedrawEvent::BusyStart => { trace!("Cursor off"); @@ -129,17 +136,22 @@ impl Editor { RedrawEvent::Flush => { trace!("Image flushed"); self.send_cursor_info(); + self.draw_command_batcher.send_batch().ok(); REDRAW_SCHEDULER.queue_next_frame(); } RedrawEvent::DefaultColorsSet { colors } => { - self.draw_command_sender.send(DrawCommand::DefaultStyleChanged(Style::new(colors))).ok(); + self.draw_command_batcher + .queue(DrawCommand::DefaultStyleChanged(Style::new(colors))) + .ok(); } RedrawEvent::HighlightAttributesDefine { id, style } => { self.defined_styles.insert(id, Arc::new(style)); } - RedrawEvent::CursorGoto { grid, column: left, row: top } => { - self.set_cursor_position(grid, left, top) - } + RedrawEvent::CursorGoto { + grid, + column: left, + row: top, + } => self.set_cursor_position(grid, left, top), RedrawEvent::Resize { grid, width, @@ -154,19 +166,12 @@ impl Editor { cells, } => { let defined_styles = &self.defined_styles; - self.windows.get_mut(&grid).map(|window| { - window.draw_grid_line( - row, - column_start, - cells, - defined_styles - ) - }); - } - RedrawEvent::Clear { grid } => { self.windows .get_mut(&grid) - .map(|window| window.clear()); + .map(|window| window.draw_grid_line(row, column_start, cells, defined_styles)); + } + RedrawEvent::Clear { grid } => { + self.windows.get_mut(&grid).map(|window| window.clear()); } RedrawEvent::Destroy { grid } => self.close_window(grid), RedrawEvent::Scroll { @@ -196,13 +201,9 @@ impl Editor { anchor_column: anchor_left, anchor_row: anchor_top, .. - } => { - self.set_window_float_position(grid, anchor_grid, anchor, anchor_left, anchor_top) - } + } => self.set_window_float_position(grid, anchor_grid, anchor, anchor_left, anchor_top), RedrawEvent::WindowHide { grid } => { - self.windows - .get(&grid) - .map(|window| window.hide()); + self.windows.get(&grid).map(|window| window.hide()); } RedrawEvent::WindowClose { grid } => self.close_window(grid), RedrawEvent::MessageSetPosition { grid, row, .. } => { @@ -215,7 +216,9 @@ impl Editor { fn close_window(&mut self, grid: u64) { if let Some(window) = self.windows.remove(&grid) { window.close(); - self.draw_command_sender.send(DrawCommand::CloseWindow(grid)).ok(); + self.draw_command_batcher + .queue(DrawCommand::CloseWindow(grid)) + .ok(); } } @@ -225,13 +228,14 @@ impl Editor { window.resize(width, height); } else { let window = Window::new( - grid, - width, - height, - None, - 0.0, - 0.0, - self.draw_command_sender.clone()); + grid, + width, + height, + None, + 0.0, + 0.0, + self.draw_command_batcher.clone(), + ); self.windows.insert(grid, window); } } @@ -246,12 +250,7 @@ impl Editor { ) { warn!("position {}", grid); if let Some(window) = self.windows.get_mut(&grid) { - window.position( - width, - height, - None, - start_left as f64, - start_top as f64); + window.position(width, height, None, start_left as f64, start_top as f64); window.show(); } else { let new_window = Window::new( @@ -261,7 +260,7 @@ impl Editor { None, start_left as f64, start_top as f64, - self.draw_command_sender.clone() + self.draw_command_batcher.clone(), ); self.windows.insert(grid, new_window); } @@ -280,9 +279,8 @@ impl Editor { if let Some(window) = self.windows.get_mut(&grid) { let width = window.get_width(); let height = window.get_height(); - let (mut modified_left, mut modified_top) = anchor_type.modified_top_left( - anchor_left, anchor_top, - width, height); + let (mut modified_left, mut modified_top) = + anchor_type.modified_top_left(anchor_left, anchor_top, width, height); if let Some((parent_left, parent_top)) = parent_position { modified_left = parent_left + modified_left; @@ -290,12 +288,17 @@ impl Editor { } window.position( - width, height, + width, + height, Some(AnchorInfo { - anchor_grid_id: anchor_grid, - anchor_type, anchor_left, anchor_top + anchor_grid_id: anchor_grid, + anchor_type, + anchor_left, + anchor_top, }), - modified_left, modified_top); + modified_left, + modified_top, + ); window.show(); } else { error!("Attempted to float window that does not exist."); @@ -304,14 +307,20 @@ impl Editor { fn set_message_position(&mut self, grid: u64, grid_top: u64) { warn!("message position {}", grid); - let parent_width = self.windows.get(&1).map(|parent| parent.get_width()).unwrap_or(1); + let parent_width = self + .windows + .get(&1) + .map(|parent| parent.get_width()) + .unwrap_or(1); if let Some(window) = self.windows.get_mut(&grid) { window.position( - parent_width, window.get_height(), + parent_width, + window.get_height(), None, 0.0, - grid_top as f64); + grid_top as f64, + ); window.show(); } else { let new_window = Window::new( @@ -321,7 +330,7 @@ impl Editor { None, 0.0, grid_top as f64, - self.draw_command_sender.clone() + self.draw_command_batcher.clone(), ); self.windows.insert(grid, new_window); } @@ -336,11 +345,18 @@ impl Editor { let (parent_anchor_left, parent_anchor_top) = self.get_window_top_left(anchor_info.anchor_grid_id)?; - let (anchor_modified_left, anchor_modified_top) = anchor_info.anchor_type.modified_top_left( - anchor_info.anchor_left, anchor_info.anchor_top, - window.get_width(), window.get_height()); + let (anchor_modified_left, anchor_modified_top) = + anchor_info.anchor_type.modified_top_left( + anchor_info.anchor_left, + anchor_info.anchor_top, + window.get_width(), + window.get_height(), + ); - Some((parent_anchor_left + anchor_modified_left, parent_anchor_top + anchor_modified_top)) + Some(( + parent_anchor_left + anchor_modified_left, + parent_anchor_top + anchor_modified_top, + )) } None => Some(window.get_grid_position()), } @@ -355,10 +371,12 @@ impl Editor { let (grid_left, grid_top) = self.cursor.grid_position; match self.get_window_top_left(self.cursor.parent_window_id) { Some((window_left, window_top)) => { - self.cursor.position = (window_left + grid_left as f64, window_top + grid_top as f64); + self.cursor.position = + (window_left + grid_left as f64, window_top + grid_top as f64); if let Some(window) = self.windows.get(&self.cursor.parent_window_id) { - let (character, double_width) = window.get_cursor_character(grid_left, grid_top); + let (character, double_width) = + window.get_cursor_character(grid_left, grid_top); self.cursor.character = character; self.cursor.double_width = double_width; } @@ -369,20 +387,28 @@ impl Editor { self.cursor.character = " ".to_string(); } } - self.draw_command_sender.send(DrawCommand::UpdateCursor(self.cursor.clone())).ok(); + self.draw_command_batcher + .queue(DrawCommand::UpdateCursor(self.cursor.clone())) + .ok(); } fn set_option(&mut self, gui_option: GuiOption) { trace!("Option set {:?}", &gui_option); if let GuiOption::GuiFont(guifont) = gui_option { - self.draw_command_sender.send(DrawCommand::FontChanged(guifont)).ok(); + self.draw_command_batcher + .queue(DrawCommand::FontChanged(guifont)) + .ok(); } } } -pub fn start_editor(redraw_event_receiver: Receiver, draw_command_sender: Sender, window_command_sender: Sender) { +pub fn start_editor( + redraw_event_receiver: Receiver, + batched_draw_command_sender: Sender>, + window_command_sender: Sender, +) { thread::spawn(move || { - let mut editor = Editor::new(draw_command_sender, window_command_sender); + let mut editor = Editor::new(batched_draw_command_sender, window_command_sender); loop { if let Ok(redraw_event) = redraw_event_receiver.recv() { diff --git a/src/editor/window.rs b/src/editor/window.rs index cb5927a..208c674 100644 --- a/src/editor/window.rs +++ b/src/editor/window.rs @@ -1,14 +1,13 @@ use std::collections::HashMap; -use std::sync::Arc; -use std::sync::mpsc::Sender; use std::fmt; +use std::sync::Arc; use log::warn; use unicode_segmentation::UnicodeSegmentation; -use super::{DrawCommand, AnchorInfo}; use super::grid::CharacterGrid; use super::style::Style; +use super::{AnchorInfo, DrawCommand, DrawCommandBatcher}; use crate::bridge::GridLineCell; #[derive(new, Clone)] @@ -18,7 +17,7 @@ pub enum WindowDrawCommand { grid_top: f64, width: u64, height: u64, - floating: bool + floating: bool, }, Cell { text: String, @@ -38,7 +37,7 @@ pub enum WindowDrawCommand { Clear, Show, Hide, - Close + Close, } impl fmt::Debug for WindowDrawCommand { @@ -64,7 +63,7 @@ pub struct Window { grid_left: f64, grid_top: f64, - draw_command_sender: Sender + draw_command_batcher: Arc, } impl Window { @@ -75,7 +74,7 @@ impl Window { anchor_info: Option, grid_left: f64, grid_top: f64, - draw_command_sender: Sender + draw_command_batcher: Arc, ) -> Window { let window = Window { grid_id, @@ -83,17 +82,19 @@ impl Window { anchor_info, grid_left, grid_top, - draw_command_sender + draw_command_batcher, }; window.send_updated_position(); window } fn send_command(&self, command: WindowDrawCommand) { - self.draw_command_sender.send(DrawCommand::Window { - grid_id: self.grid_id, - command - }).ok(); + self.draw_command_batcher + .queue(DrawCommand::Window { + grid_id: self.grid_id, + command, + }) + .ok(); } fn send_updated_position(&self) { @@ -132,7 +133,14 @@ impl Window { (self.grid_left, self.grid_top) } - pub fn position(&mut self, width: u64, height: u64, anchor_info: Option, grid_left: f64, grid_top: f64) { + pub fn position( + &mut self, + width: u64, + height: u64, + anchor_info: Option, + grid_left: f64, + grid_top: f64, + ) { self.grid.resize(width, height); self.anchor_info = anchor_info; self.grid_left = grid_left; @@ -151,17 +159,13 @@ impl Window { column_pos: &mut u64, cell: GridLineCell, defined_styles: &HashMap>, - previous_style: &mut Option>, + previous_style: &mut Option>, ) { // Get the defined style from the style list let style = match cell.highlight_id { Some(0) => None, - Some(style_id) => { - defined_styles.get(&style_id).cloned() - }, - None => { - previous_style.clone() - }, + Some(style_id) => defined_styles.get(&style_id).cloned(), + None => previous_style.clone(), }; // Compute text @@ -185,16 +189,14 @@ impl Window { *column_pos += text.graphemes(true).count() as u64; } - if let Some(style) = style { - *previous_style = Some(style); - } + *previous_style = style; } fn send_draw_command( &mut self, row_index: u64, line_start: u64, - current_start: u64 + current_start: u64, ) -> Option { let row = self.grid.row(row_index).unwrap(); @@ -217,7 +219,6 @@ impl Window { } } - let mut draw_command_end_index = current_start; for possible_end_index in draw_command_start_index..self.grid.width { if let Some((_, possible_end_style)) = &row[possible_end_index as usize] { @@ -242,7 +243,7 @@ impl Window { cell_width: draw_command_end_index - draw_command_start_index + 1, window_left: draw_command_start_index, window_top: row_index, - style: style.clone() + style: style.clone(), }); Some(draw_command_end_index + 1) @@ -253,7 +254,7 @@ impl Window { row: u64, column_start: u64, cells: Vec, - defined_styles: &HashMap> + defined_styles: &HashMap>, ) { let mut previous_style = None; if row < self.grid.height { @@ -297,7 +298,12 @@ impl Window { }; self.send_command(WindowDrawCommand::Scroll { - top, bot, left, right, rows, cols + top, + bot, + left, + right, + rows, + cols, }); // Scrolls must not only translate the rendered texture, but also must move the grid data diff --git a/src/main.rs b/src/main.rs index eb2973f..f5f02b8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,14 +18,14 @@ extern crate rust_embed; #[macro_use] extern crate lazy_static; -use std::sync::Arc; +use std::process; use std::sync::atomic::AtomicBool; use std::sync::mpsc::channel; -use std::process; +use std::sync::Arc; use window::window_geometry; -use bridge::start_bridge; +use bridge::start_bridge; use editor::start_editor; use window::start_window; @@ -132,11 +132,25 @@ fn main() { let running = Arc::new(AtomicBool::new(true)); let (redraw_event_sender, redraw_event_receiver) = channel(); - let (draw_command_sender, draw_command_receiver) = channel(); + let (batched_draw_command_sender, batched_draw_command_receiver) = channel(); let (ui_command_sender, ui_command_receiver) = channel(); let (window_command_sender, window_command_receiver) = channel(); - start_bridge(ui_command_sender.clone(), ui_command_receiver, redraw_event_sender, running.clone()); - start_editor(redraw_event_receiver, draw_command_sender, window_command_sender); - start_window(draw_command_receiver, window_command_receiver, ui_command_sender, running.clone()); + start_bridge( + ui_command_sender.clone(), + ui_command_receiver, + redraw_event_sender, + running.clone(), + ); + start_editor( + redraw_event_receiver, + batched_draw_command_sender, + window_command_sender, + ); + start_window( + batched_draw_command_receiver, + window_command_receiver, + ui_command_sender, + running.clone(), + ); } diff --git a/src/renderer/cursor_renderer/cursor_vfx.rs b/src/renderer/cursor_renderer/cursor_vfx.rs index 31ab2bc..058666d 100644 --- a/src/renderer/cursor_renderer/cursor_vfx.rs +++ b/src/renderer/cursor_renderer/cursor_vfx.rs @@ -2,8 +2,8 @@ use log::error; use skulpin::skia_safe::{paint::Style, BlendMode, Canvas, Color, Paint, Point, Rect}; use super::CursorSettings; -use crate::renderer::animation_utils::*; use crate::editor::{Colors, Cursor}; +use crate::renderer::animation_utils::*; use crate::settings::*; pub trait CursorVfx { diff --git a/src/renderer/cursor_renderer/mod.rs b/src/renderer/cursor_renderer/mod.rs index b84ca8e..4250df9 100644 --- a/src/renderer/cursor_renderer/mod.rs +++ b/src/renderer/cursor_renderer/mod.rs @@ -5,8 +5,8 @@ use skulpin::skia_safe::{Canvas, Paint, Path, Point}; use crate::editor::{Colors, Cursor, CursorShape}; use crate::redraw_scheduler::REDRAW_SCHEDULER; -use crate::renderer::CachingShaper; use crate::renderer::animation_utils::*; +use crate::renderer::CachingShaper; use crate::settings::*; use blink::*; @@ -265,8 +265,8 @@ impl CursorRenderer { let in_insert_mode = false; // { - // let editor = EDITOR.lock(); - // matches!(editor.current_mode, EditorMode::Insert) + // let editor = EDITOR.lock(); + // matches!(editor.current_mode, EditorMode::Insert) // }; let destination: Point = (grid_x as f32 * font_width, grid_y as f32 * font_height).into(); @@ -277,7 +277,9 @@ impl CursorRenderer { self.previous_cursor_shape = new_cursor.clone(); self.set_cursor_shape( &new_cursor.unwrap(), - self.cursor.cell_percentage.unwrap_or(DEFAULT_CELL_PERCENTAGE), + self.cursor + .cell_percentage + .unwrap_or(DEFAULT_CELL_PERCENTAGE), ); if let Some(vfx) = self.cursor_vfx.as_mut() { diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index b237068..e98838d 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,28 +1,25 @@ use std::collections::HashMap; -use std::sync::Arc; use std::sync::mpsc::Receiver; +use std::sync::Arc; -use log::{trace, warn, error}; -use skulpin::skia_safe::{ - colors, dash_path_effect, Canvas, Paint, Rect, BlendMode, Color -}; +use log::{error, trace, warn}; +use skulpin::skia_safe::{colors, dash_path_effect, BlendMode, Canvas, Color, Paint, Rect}; use skulpin::CoordinateSystemHelper; +pub mod animation_utils; mod caching_shaper; -mod rendered_window; pub mod cursor_renderer; pub mod font_options; -pub mod animation_utils; +mod rendered_window; pub use caching_shaper::CachingShaper; pub use font_options::*; -use crate::editor::{Style, Colors, DrawCommand, WindowDrawCommand}; +use crate::editor::{Colors, DrawCommand, Style, WindowDrawCommand}; use crate::settings::*; use cursor_renderer::CursorRenderer; use rendered_window::RenderedWindow; - // ---------------------------------------------------------------------------- #[derive(Clone)] @@ -39,14 +36,19 @@ pub fn initialize_settings() { floating_blur: true, }); - register_nvim_setting!("window_animation_length", RendererSettings::animation_length); - register_nvim_setting!("floating_window_opacity", RendererSettings::floating_opacity); + register_nvim_setting!( + "window_animation_length", + RendererSettings::animation_length + ); + register_nvim_setting!( + "floating_window_opacity", + RendererSettings::floating_opacity + ); register_nvim_setting!("floating_window_blur", RendererSettings::floating_opacity); } // ---------------------------------------------------------------------------- - pub struct Renderer { rendered_windows: HashMap, cursor_renderer: CursorRenderer, @@ -58,11 +60,11 @@ pub struct Renderer { pub font_width: f32, pub font_height: f32, pub window_regions: Vec<(u64, Rect)>, - pub draw_command_receiver: Receiver, + pub batched_draw_command_receiver: Receiver>, } impl Renderer { - pub fn new(draw_command_receiver: Receiver) -> Renderer { + pub fn new(batched_draw_command_receiver: Receiver>) -> Renderer { let rendered_windows = HashMap::new(); let cursor_renderer = CursorRenderer::new(); let settings = SETTINGS.get::(); @@ -89,7 +91,7 @@ impl Renderer { font_width, font_height, window_regions, - draw_command_receiver, + batched_draw_command_receiver, } } @@ -124,7 +126,8 @@ impl Renderer { let region = self.compute_text_region(grid_pos, cell_width); let style = style.as_ref().unwrap_or(&self.default_style); - self.paint.set_color(style.background(&self.default_style.colors).to_color()); + self.paint + .set_color(style.background(&self.default_style.colors).to_color()); canvas.draw_rect(region, &self.paint); } @@ -205,44 +208,49 @@ impl Renderer { match draw_command { DrawCommand::Window { grid_id, - command: WindowDrawCommand::Close + command: WindowDrawCommand::Close, } => { self.rendered_windows.remove(&grid_id); - }, - DrawCommand::Window { - grid_id, - command - } => { + } + DrawCommand::Window { grid_id, command } => { if let Some(rendered_window) = self.rendered_windows.remove(&grid_id) { warn!("Window positioned {}", grid_id); let rendered_window = rendered_window.handle_window_draw_command(self, command); self.rendered_windows.insert(grid_id, rendered_window); - } else if let WindowDrawCommand::Position { - grid_left, grid_top, - width, height, .. - } = command { + } else if let WindowDrawCommand::Position { + grid_left, + grid_top, + width, + height, + .. + } = command + { warn!("Created window {}", grid_id); let new_window = RenderedWindow::new( - root_canvas, &self, grid_id, - (grid_left as f32, grid_top as f32).into(), - width, height); + root_canvas, + &self, + grid_id, + (grid_left as f32, grid_top as f32).into(), + width, + height, + ); self.rendered_windows.insert(grid_id, new_window); } else { error!("WindowDrawCommand sent for uninitialized grid {}", grid_id); } - }, + } DrawCommand::UpdateCursor(new_cursor) => { self.cursor_renderer.update_cursor(new_cursor); - }, + } DrawCommand::FontChanged(new_font) => { if self.update_font(&new_font) { // Resize all the grids } - }, + } DrawCommand::DefaultStyleChanged(new_style) => { self.default_style = Arc::new(new_style); - }, - _ => { } + } + _ => {} } } @@ -255,7 +263,12 @@ impl Renderer { trace!("Rendering"); let mut font_changed = false; - let draw_commands: Vec = self.draw_command_receiver.try_iter().collect(); + let draw_commands: Vec = self + .batched_draw_command_receiver + .try_iter() // Iterator of Vec of DrawCommand + .map(|batch| batch.into_iter()) // Iterator of Iterator of DrawCommand + .flatten() // Iterator of DrawCommand + .collect(); // Vec of DrawCommand for draw_command in draw_commands.into_iter() { if let DrawCommand::FontChanged(_) = draw_command { font_changed = true; @@ -263,20 +276,36 @@ impl Renderer { self.handle_draw_command(root_canvas, draw_command); } - root_canvas.clear(self.default_style.colors.background.clone().unwrap().to_color()); + root_canvas.clear( + self.default_style + .colors + .background + .clone() + .unwrap() + .to_color(), + ); coordinate_system_helper.use_logical_coordinates(root_canvas); let windows: Vec<&mut RenderedWindow> = { - let (mut root_windows, mut floating_windows): (Vec<&mut RenderedWindow>, Vec<&mut RenderedWindow>) = self.rendered_windows + let (mut root_windows, mut floating_windows): ( + Vec<&mut RenderedWindow>, + Vec<&mut RenderedWindow>, + ) = self + .rendered_windows .values_mut() .filter(|window| !window.hidden) .partition(|window| !window.floating); - root_windows.sort_by(|window_a, window_b| window_a.id.partial_cmp(&window_b.id).unwrap()); - floating_windows.sort_by(|window_a, window_b| window_a.id.partial_cmp(&window_b.id).unwrap()); + root_windows + .sort_by(|window_a, window_b| window_a.id.partial_cmp(&window_b.id).unwrap()); + floating_windows + .sort_by(|window_a, window_b| window_a.id.partial_cmp(&window_b.id).unwrap()); - root_windows.into_iter().chain(floating_windows.into_iter()).collect() + root_windows + .into_iter() + .chain(floating_windows.into_iter()) + .collect() }; let settings = &self.settings; diff --git a/src/renderer/rendered_window.rs b/src/renderer/rendered_window.rs index 0fdbddc..3707117 100644 --- a/src/renderer/rendered_window.rs +++ b/src/renderer/rendered_window.rs @@ -1,14 +1,11 @@ +use skulpin::skia_safe::canvas::{SaveLayerRec, SrcRectConstraint}; use skulpin::skia_safe::gpu::SurfaceOrigin; use skulpin::skia_safe::{ - Budgeted, Canvas, ImageInfo, Rect, Surface, Point, Paint, Color, BlendMode, image_filters::blur -}; -use skulpin::skia_safe::canvas::{ - SaveLayerRec, - SrcRectConstraint + image_filters::blur, BlendMode, Budgeted, Canvas, Color, ImageInfo, Paint, Point, Rect, Surface, }; -use super::{Renderer, RendererSettings}; use super::animation_utils::*; +use super::{Renderer, RendererSettings}; use crate::editor::WindowDrawCommand; use crate::redraw_scheduler::REDRAW_SCHEDULER; @@ -18,7 +15,10 @@ fn build_window_surface( grid_width: u64, grid_height: u64, ) -> Surface { - let dimensions = ((grid_width as f32 * renderer.font_width) as i32, (grid_height as f32 * renderer.font_height) as i32); + let dimensions = ( + (grid_width as f32 * renderer.font_width) as i32, + (grid_height as f32 * renderer.font_height) as i32, + ); let mut context = parent_canvas.gpu_context().unwrap(); let budgeted = Budgeted::Yes; let parent_image_info = parent_canvas.image_info(); @@ -39,9 +39,26 @@ fn build_window_surface( None, ) .expect("Could not create surface"); - let canvas = surface.canvas(); + surface +} - canvas.clear(renderer.default_style.colors.background.clone().unwrap().to_color()); +fn build_background_window_surface( + parent_canvas: &mut Canvas, + renderer: &Renderer, + grid_width: u64, + grid_height: u64, +) -> Surface { + let mut surface = build_window_surface(parent_canvas, renderer, grid_width, grid_height); + let canvas = surface.canvas(); + canvas.clear( + renderer + .default_style + .colors + .background + .clone() + .unwrap() + .to_color(), + ); surface } @@ -52,18 +69,28 @@ pub struct RenderedWindow { pub hidden: bool, pub floating: bool, - grid_width: u64, grid_height: u64, + grid_width: u64, + grid_height: u64, grid_start_position: Point, grid_current_position: Point, grid_destination: Point, - t: f32 + t: f32, } impl RenderedWindow { - pub fn new(parent_canvas: &mut Canvas, renderer: &Renderer, id: u64, grid_position: Point, grid_width: u64, grid_height: u64) -> RenderedWindow { - let background_surface = build_window_surface(parent_canvas, renderer, grid_width, grid_height); - let foreground_surface = build_window_surface(parent_canvas, renderer, grid_width, grid_height); + pub fn new( + parent_canvas: &mut Canvas, + renderer: &Renderer, + id: u64, + grid_position: Point, + grid_width: u64, + grid_height: u64, + ) -> RenderedWindow { + let background_surface = + build_background_window_surface(parent_canvas, renderer, grid_width, grid_height); + let foreground_surface = + build_window_surface(parent_canvas, renderer, grid_width, grid_height); RenderedWindow { background_surface, @@ -78,15 +105,11 @@ impl RenderedWindow { grid_start_position: grid_position, grid_current_position: grid_position, grid_destination: grid_position, - t: 2.0 // 2.0 is out of the 0.0 to 1.0 range and stops animation + t: 2.0, // 2.0 is out of the 0.0 to 1.0 range and stops animation } } - pub fn update( - &mut self, - settings: &RendererSettings, - dt: f32 - ) -> bool { + pub fn update(&mut self, settings: &RendererSettings, dt: f32) -> bool { if (self.t - 1.0).abs() < std::f32::EPSILON { return false; } @@ -114,9 +137,12 @@ impl RenderedWindow { settings: &RendererSettings, font_width: f32, font_height: f32, - dt: f32 - ) -> (u64, Rect) { - let current_pixel_position = Point::new(self.grid_current_position.x * font_width, self.grid_current_position.y * font_height); + dt: f32, + ) -> (u64, Rect) { + let current_pixel_position = Point::new( + self.grid_current_position.x * font_width, + self.grid_current_position.y * font_height, + ); let image_width = (self.grid_width as f32 * font_width) as i32; let image_height = (self.grid_height as f32 * font_height) as i32; @@ -132,9 +158,7 @@ impl RenderedWindow { if self.floating && settings.floating_blur { let blur = blur((2.0, 2.0), None, None, None).unwrap(); - let save_layer_rec = SaveLayerRec::default() - .backdrop(&blur) - .bounds(®ion); + let save_layer_rec = SaveLayerRec::default().backdrop(&blur).bounds(®ion); root_canvas.save_layer(&save_layer_rec); } @@ -146,12 +170,20 @@ impl RenderedWindow { paint.set_color(Color::from_argb(a, 255, 255, 255)); } - self.background_surface.draw(root_canvas.as_mut(), (current_pixel_position.x, current_pixel_position.y), Some(&paint)); + self.background_surface.draw( + root_canvas.as_mut(), + (current_pixel_position.x, current_pixel_position.y), + Some(&paint), + ); let mut paint = Paint::default(); paint.set_blend_mode(BlendMode::SrcOver); - self.foreground_surface.draw(root_canvas.as_mut(), (current_pixel_position.x, current_pixel_position.y), Some(&paint)); + self.foreground_surface.draw( + root_canvas.as_mut(), + (current_pixel_position.x, current_pixel_position.y), + Some(&paint), + ); if self.floating { root_canvas.restore(); @@ -161,28 +193,38 @@ impl RenderedWindow { let window_position = current_pixel_position.clone(); - (self.id, Rect::from_point_and_size(window_position, (image_width as f32, image_height as f32))) + ( + self.id, + Rect::from_point_and_size(window_position, (image_width as f32, image_height as f32)), + ) } - pub fn handle_window_draw_command(mut self, renderer: &mut Renderer, draw_command: WindowDrawCommand) -> Self { + pub fn handle_window_draw_command( + mut self, + renderer: &mut Renderer, + draw_command: WindowDrawCommand, + ) -> Self { match draw_command { WindowDrawCommand::Position { - grid_left, grid_top, - width: grid_width, + grid_left, + grid_top, + width: grid_width, height: grid_height, - floating + floating, } => { let new_destination: Point = (grid_left as f32, grid_top as f32).into(); if self.grid_destination != new_destination { - if self.grid_start_position.x.abs() > f32::EPSILON || self.grid_start_position.y.abs() > f32::EPSILON { + if self.grid_start_position.x.abs() > f32::EPSILON + || self.grid_start_position.y.abs() > f32::EPSILON + { self.t = 0.0; // Reset animation as we have a new destination. self.grid_start_position = self.grid_current_position; self.grid_destination = new_destination; } else { - // We don't want to animate since the window is animating out of the start location, + // We don't want to animate since the window is animating out of the start location, // so we set t to 2.0 to stop animations. - self.t = 2.0; + self.t = 2.0; self.grid_start_position = new_destination; self.grid_destination = new_destination; } @@ -191,13 +233,23 @@ impl RenderedWindow { if grid_width != self.grid_width || grid_height != self.grid_height { { let mut old_background = self.background_surface; - self.background_surface = build_window_surface(old_background.canvas(), &renderer, grid_width, grid_height); + self.background_surface = build_background_window_surface( + old_background.canvas(), + &renderer, + grid_width, + grid_height, + ); old_background.draw(self.background_surface.canvas(), (0.0, 0.0), None); } { let mut old_foreground = self.foreground_surface; - self.foreground_surface = build_window_surface(old_foreground.canvas(), &renderer, grid_width, grid_height); + self.foreground_surface = build_window_surface( + old_foreground.canvas(), + &renderer, + grid_width, + grid_height, + ); old_foreground.draw(self.foreground_surface.canvas(), (0.0, 0.0), None); } @@ -213,9 +265,13 @@ impl RenderedWindow { self.grid_start_position = new_destination; self.grid_destination = new_destination; } - }, + } WindowDrawCommand::Cell { - text, cell_width, window_left, window_top, style + text, + cell_width, + window_left, + window_top, + style, } => { let grid_position = (window_left, window_top); @@ -225,7 +281,7 @@ impl RenderedWindow { &mut background_canvas, grid_position, cell_width, - &style + &style, ); } @@ -239,15 +295,21 @@ impl RenderedWindow { &style, ); } - }, + } WindowDrawCommand::Scroll { - top, bot, left, right, rows, cols + top, + bot, + left, + right, + rows, + cols, } => { let scrolled_region = Rect::new( left as f32 * renderer.font_width, top as f32 * renderer.font_height, right as f32 * renderer.font_width, - bot as f32 * renderer.font_height); + bot as f32 * renderer.font_height, + ); { let background_snapshot = self.background_surface.image_snapshot(); @@ -257,9 +319,17 @@ impl RenderedWindow { background_canvas.clip_rect(scrolled_region, None, Some(false)); let mut translated_region = scrolled_region.clone(); - translated_region.offset((-cols as f32 * renderer.font_width, -rows as f32 * renderer.font_height)); - - background_canvas.draw_image_rect(background_snapshot, Some((&scrolled_region, SrcRectConstraint::Fast)), translated_region, &renderer.paint); + translated_region.offset(( + -cols as f32 * renderer.font_width, + -rows as f32 * renderer.font_height, + )); + + background_canvas.draw_image_rect( + background_snapshot, + Some((&scrolled_region, SrcRectConstraint::Fast)), + translated_region, + &renderer.paint, + ); background_canvas.restore(); } @@ -272,20 +342,38 @@ impl RenderedWindow { foreground_canvas.clip_rect(scrolled_region, None, Some(false)); let mut translated_region = scrolled_region.clone(); - translated_region.offset((-cols as f32 * renderer.font_width, -rows as f32 * renderer.font_height)); - - foreground_canvas.draw_image_rect(foreground_snapshot, Some((&scrolled_region, SrcRectConstraint::Fast)), translated_region, &renderer.paint); + translated_region.offset(( + -cols as f32 * renderer.font_width, + -rows as f32 * renderer.font_height, + )); + + foreground_canvas.draw_image_rect( + foreground_snapshot, + Some((&scrolled_region, SrcRectConstraint::Fast)), + translated_region, + &renderer.paint, + ); foreground_canvas.restore(); } - }, + } WindowDrawCommand::Clear => { let background_canvas = self.background_surface.canvas(); - self.background_surface = build_window_surface(background_canvas, &renderer, self.grid_width, self.grid_height); + self.background_surface = build_background_window_surface( + background_canvas, + &renderer, + self.grid_width, + self.grid_height, + ); let foreground_canvas = self.foreground_surface.canvas(); - self.foreground_surface = build_window_surface(foreground_canvas, &renderer, self.grid_width, self.grid_height); - }, + self.foreground_surface = build_window_surface( + foreground_canvas, + &renderer, + self.grid_width, + self.grid_height, + ); + } WindowDrawCommand::Show => { if self.hidden { self.hidden = false; @@ -293,7 +381,7 @@ impl RenderedWindow { self.grid_start_position = self.grid_destination; self.grid_destination = self.grid_destination; } - }, + } WindowDrawCommand::Hide => self.hidden = true, _ => {} }; diff --git a/src/settings/mod.rs b/src/settings/mod.rs index 3ab09c2..12214c2 100644 --- a/src/settings/mod.rs +++ b/src/settings/mod.rs @@ -170,11 +170,10 @@ impl Settings { ), name ); - nvim.command(&vimscript) - .unwrap_or_explained_panic(&format!( - "Could not setup setting notifier for {}", - name - )); + nvim.command(&vimscript).unwrap_or_explained_panic(&format!( + "Could not setup setting notifier for {}", + name + )); } } @@ -191,31 +190,11 @@ impl Settings { #[cfg(test)] mod tests { + use neovim_lib::{Neovim, NeovimApi, Session, UiAttachOptions}; use super::*; use crate::bridge::create_nvim_command; - use async_trait::async_trait; - use nvim_rs::create::tokio as create; - use nvim_rs::{compat::tokio::Compat, Handler, Neovim}; - - #[derive(Clone)] - pub struct NeovimHandler(); - - #[async_trait] - impl Handler for NeovimHandler { - type Writer = Compat; - - async fn handle_notify( - &self, - _event_name: String, - _arguments: Vec, - _neovim: Neovim>, - ) { - } - } - - use tokio; #[test] fn test_set_setting_handlers() { @@ -288,8 +267,8 @@ mod tests { assert_eq!(v2, r2); } - #[tokio::test] - async fn test_read_initial_values() { + #[test] + fn test_read_initial_values() { let settings = Settings::new(); let v1: String = "foo".to_string(); @@ -298,12 +277,12 @@ mod tests { let v4: String = format!("neovide_{}", v1); let v5: String = format!("neovide_{}", v2); - let (nvim, _, _) = create::new_child_cmd(&mut create_nvim_command(), NeovimHandler()) - .await - .unwrap_or_explained_panic("Could not locate or start the neovim process"); + let mut session = Session::new_child_cmd(&mut create_nvim_command()) + .unwrap_or_explained_panic("Could not locate or start neovim process"); + session.start_event_loop_channel(); + let mut nvim = Neovim::new(session); - nvim.set_var(&v4, Value::from(v2.clone())).await.ok(); - println!("v4 set"); + nvim.set_var(&v4, Value::from(v2.clone())).unwrap(); fn noop_update(_v: Value) {} @@ -327,10 +306,10 @@ mod tests { settings.readers.force_unlock_write(); } - settings.read_initial_values(&nvim).await; + settings.read_initial_values(&mut nvim); - let rt1 = nvim.get_var(&v4).await.unwrap(); - let rt2 = nvim.get_var(&v5).await.unwrap(); + let rt1 = nvim.get_var(&v4).unwrap(); + let rt2 = nvim.get_var(&v5).unwrap(); let r1 = rt1.as_str().unwrap(); let r2 = rt2.as_str().unwrap(); diff --git a/src/window.rs b/src/window.rs index 1a17dd3..ecae8e5 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,28 +1,28 @@ +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::mpsc::{Receiver, Sender}; +use std::sync::Arc; use std::thread::sleep; use std::time::{Duration, Instant}; -use std::sync::Arc; -use std::sync::atomic::{Ordering, AtomicBool}; -use std::sync::mpsc::{Sender, Receiver}; -use log::{debug, error, warn, info, trace}; +use log::{debug, error, info, trace, warn}; +use skulpin::ash::prelude::VkResult; use skulpin::sdl2; use skulpin::sdl2::event::{Event, WindowEvent}; use skulpin::sdl2::keyboard::Keycode; use skulpin::sdl2::video::FullscreenType; use skulpin::sdl2::Sdl; -use skulpin::ash::prelude::VkResult; use skulpin::{ CoordinateSystem, LogicalSize, PhysicalSize, PresentMode, Renderer as SkulpinRenderer, RendererBuilder, Sdl2Window, Window, }; -use crate::editor::{DrawCommand, WindowCommand}; use crate::bridge::{produce_neovim_keybinding_string, UiCommand}; +use crate::editor::{DrawCommand, WindowCommand}; +use crate::error_handling::ResultPanicExplanation; use crate::redraw_scheduler::REDRAW_SCHEDULER; use crate::renderer::Renderer; use crate::settings::*; use crate::INITIAL_DIMENSIONS; -use crate::error_handling::ResultPanicExplanation; #[derive(RustEmbed)] #[folder = "assets/"] @@ -37,15 +37,21 @@ fn windows_fix_dpi() { } } -fn handle_new_grid_size(new_size: LogicalSize, renderer: &Renderer, ui_command_sender: &Sender) { +fn handle_new_grid_size( + new_size: LogicalSize, + renderer: &Renderer, + ui_command_sender: &Sender, +) { if new_size.width > 0 && new_size.height > 0 { let new_width = ((new_size.width + 1) as f32 / renderer.font_width) as u32; let new_height = ((new_size.height + 1) as f32 / renderer.font_height) as u32; // Add 1 here to make sure resizing doesn't change the grid size on startup - ui_command_sender.send(UiCommand::Resize { - width: new_width, - height: new_height, - }).ok(); + ui_command_sender + .send(UiCommand::Resize { + width: new_width, + height: new_height, + }) + .ok(); } } @@ -65,7 +71,7 @@ struct WindowWrapper { cached_size: (u32, u32), cached_position: (i32, i32), ui_command_sender: Sender, - running: Arc + running: Arc, } pub fn window_geometry() -> Result<(u64, u64), String> { @@ -111,7 +117,11 @@ pub fn window_geometry_or_default() -> (u64, u64) { } impl WindowWrapper { - pub fn new(ui_command_sender: Sender, draw_command_receiver: Receiver, running: Arc) -> WindowWrapper { + pub fn new( + ui_command_sender: Sender, + batched_draw_command_receiver: Receiver>, + running: Arc, + ) -> WindowWrapper { let context = sdl2::init().expect("Failed to initialize sdl2"); let video_subsystem = context .video() @@ -120,7 +130,7 @@ impl WindowWrapper { let (width, height) = window_geometry_or_default(); - let renderer = Renderer::new(draw_command_receiver); + let renderer = Renderer::new(batched_draw_command_receiver); let logical_size = LogicalSize { width: (width as f32 * renderer.font_width) as u32, height: (height as f32 * renderer.font_height + 1.0) as u32, @@ -172,7 +182,7 @@ impl WindowWrapper { cached_size: (0, 0), cached_position: (0, 0), ui_command_sender, - running + running, } } @@ -270,28 +280,36 @@ impl WindowWrapper { if let Some(keybinding_string) = produce_neovim_keybinding_string(keycode, text, modifiers) { - self.ui_command_sender.send(UiCommand::Keyboard(keybinding_string)).unwrap_or_explained_panic( - "Could not send UI command from the window system to the neovim process.", - ); + self.ui_command_sender + .send(UiCommand::Keyboard(keybinding_string)) + .unwrap_or_explained_panic( + "Could not send UI command from the window system to the neovim process.", + ); } } pub fn handle_pointer_motion(&mut self, x: i32, y: i32) { let previous_position = self.mouse_position; let sdl_window_wrapper = Sdl2Window::new(&self.window); - let logical_position = PhysicalSize::new(x as u32, y as u32) - .to_logical(sdl_window_wrapper.scale_factor()); + let logical_position = + PhysicalSize::new(x as u32, y as u32).to_logical(sdl_window_wrapper.scale_factor()); let mut top_window_position = (0.0, 0.0); let mut top_grid_position = None; for (grid_id, window_region) in self.renderer.window_regions.iter() { - if logical_position.width >= window_region.left as u32 && logical_position.width < window_region.right as u32 && - logical_position.height >= window_region.top as u32 && logical_position.height < window_region.bottom as u32 { + if logical_position.width >= window_region.left as u32 + && logical_position.width < window_region.right as u32 + && logical_position.height >= window_region.top as u32 + && logical_position.height < window_region.bottom as u32 + { top_window_position = (window_region.left, window_region.top); top_grid_position = Some(( - grid_id, - LogicalSize::new(logical_position.width - window_region.left as u32, logical_position.height - window_region.top as u32) + grid_id, + LogicalSize::new( + logical_position.width - window_region.left as u32, + logical_position.height - window_region.top as u32, + ), )); } } @@ -300,40 +318,48 @@ impl WindowWrapper { self.grid_id_under_mouse = *grid_id; self.mouse_position = LogicalSize::new( (grid_position.width as f32 / self.renderer.font_width) as u32, - (grid_position.height as f32 / self.renderer.font_height) as u32 + (grid_position.height as f32 / self.renderer.font_height) as u32, ); if self.mouse_enabled && self.mouse_down && previous_position != self.mouse_position { let (window_left, window_top) = top_window_position; - let adjusted_drag_left = self.mouse_position.width + (window_left / self.renderer.font_width) as u32; - let adjusted_drag_top = self.mouse_position.height + (window_top / self.renderer.font_height) as u32; - - self.ui_command_sender.send(UiCommand::Drag { - grid_id: self.grid_id_under_mouse, - position: (adjusted_drag_left, adjusted_drag_top), - }).ok(); + let adjusted_drag_left = + self.mouse_position.width + (window_left / self.renderer.font_width) as u32; + let adjusted_drag_top = + self.mouse_position.height + (window_top / self.renderer.font_height) as u32; + + self.ui_command_sender + .send(UiCommand::Drag { + grid_id: self.grid_id_under_mouse, + position: (adjusted_drag_left, adjusted_drag_top), + }) + .ok(); } } } pub fn handle_pointer_down(&mut self) { if self.mouse_enabled { - self.ui_command_sender.send(UiCommand::MouseButton { - action: String::from("press"), - grid_id: self.grid_id_under_mouse, - position: (self.mouse_position.width, self.mouse_position.height), - }).ok(); + self.ui_command_sender + .send(UiCommand::MouseButton { + action: String::from("press"), + grid_id: self.grid_id_under_mouse, + position: (self.mouse_position.width, self.mouse_position.height), + }) + .ok(); } self.mouse_down = true; } pub fn handle_pointer_up(&mut self) { if self.mouse_enabled { - self.ui_command_sender.send(UiCommand::MouseButton { - action: String::from("release"), - grid_id: self.grid_id_under_mouse, - position: (self.mouse_position.width, self.mouse_position.height), - }).ok(); + self.ui_command_sender + .send(UiCommand::MouseButton { + action: String::from("release"), + grid_id: self.grid_id_under_mouse, + position: (self.mouse_position.width, self.mouse_position.height), + }) + .ok(); } self.mouse_down = false; } @@ -350,11 +376,13 @@ impl WindowWrapper { }; if let Some(input_type) = vertical_input_type { - self.ui_command_sender.send(UiCommand::Scroll { - direction: input_type.to_string(), - grid_id: self.grid_id_under_mouse, - position: (self.mouse_position.width, self.mouse_position.height), - }).ok(); + self.ui_command_sender + .send(UiCommand::Scroll { + direction: input_type.to_string(), + grid_id: self.grid_id_under_mouse, + position: (self.mouse_position.width, self.mouse_position.height), + }) + .ok(); } let horizontal_input_type = match y { @@ -364,11 +392,13 @@ impl WindowWrapper { }; if let Some(input_type) = horizontal_input_type { - self.ui_command_sender.send(UiCommand::Scroll { - direction: input_type.to_string(), - grid_id: self.grid_id_under_mouse, - position: (self.mouse_position.width, self.mouse_position.height), - }).ok(); + self.ui_command_sender + .send(UiCommand::Scroll { + direction: input_type.to_string(), + grid_id: self.grid_id_under_mouse, + position: (self.mouse_position.width, self.mouse_position.height), + }) + .ok(); } } @@ -396,12 +426,14 @@ impl WindowWrapper { if REDRAW_SCHEDULER.should_draw() || SETTINGS.get::().no_idle { let renderer = &mut self.renderer; - self.skulpin_renderer - .draw(&sdl_window_wrapper, |canvas, coordinate_system_helper| { + self.skulpin_renderer.draw( + &sdl_window_wrapper, + |canvas, coordinate_system_helper| { if renderer.draw_frame(canvas, &coordinate_system_helper, dt) { handle_new_grid_size(current_size, &renderer, &ui_command_sender); } - })?; + }, + )?; Ok(true) } else { @@ -436,8 +468,17 @@ pub fn initialize_settings() { register_nvim_setting!("fullscreen", WindowSettings::fullscreen); } -pub fn start_window(draw_command_receiver: Receiver, window_command_receiver: Receiver, ui_command_sender: Sender, running: Arc) { - let mut window = WindowWrapper::new(ui_command_sender.clone(), draw_command_receiver, running.clone()); +pub fn start_window( + batched_draw_command_receiver: Receiver>, + window_command_receiver: Receiver, + ui_command_sender: Sender, + running: Arc, +) { + let mut window = WindowWrapper::new( + ui_command_sender.clone(), + batched_draw_command_receiver, + running.clone(), + ); info!("Starting window event loop"); let mut event_pump = window @@ -507,14 +548,16 @@ pub fn start_window(draw_command_receiver: Receiver, window_command for window_command in window_command_receiver.try_iter() { match window_command { WindowCommand::TitleChanged(new_title) => window.handle_title_changed(new_title), - WindowCommand::SetMouseEnabled(mouse_enabled) => window.mouse_enabled = mouse_enabled, + WindowCommand::SetMouseEnabled(mouse_enabled) => { + window.mouse_enabled = mouse_enabled + } } } match window.draw_frame(dt) { Ok(animating) => { was_animating = animating; - }, + } Err(error) => { error!("Render failed: {}", error); break;