use global lazy_static variables to handle modules instead of passing via reference

macos-click-through
Keith Simmons 5 years ago
parent e4dd7e572b
commit b4c392997e

1
Cargo.lock generated

@ -1476,6 +1476,7 @@ dependencies = [
"euclid",
"font-kit",
"image",
"lazy_static",
"lru",
"msgbox",
"nvim-rs",

@ -22,6 +22,7 @@ image = "0.22.3"
nvim-rs = { git = "https://github.com/KillTheMule/nvim-rs", branch = "futures", features = [ "use_tokio" ] }
tokio = { version = "0.2.9", features = [ "blocking", "process", "time" ] }
async-trait = "0.1.18"
lazy_static = "1.4.0"
[build-dependencies]
winres = "0.1.11"

@ -6,11 +6,11 @@ use async_trait::async_trait;
use tokio::process::ChildStdin;
use crate::error_handling::ResultPanicExplanation;
use crate::editor::Editor;
use crate::editor::{EDITOR, Editor};
use super::events::parse_neovim_event;
#[derive(Clone)]
pub struct NeovimHandler(pub Arc<Mutex<Editor>>);
pub struct NeovimHandler { }
#[async_trait]
impl Handler for NeovimHandler {
@ -20,7 +20,7 @@ impl Handler for NeovimHandler {
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();
let mut editor = EDITOR.lock().unwrap();
editor.handle_redraw_event(event);
}
}

@ -15,10 +15,15 @@ use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
pub use events::*;
pub use keybindings::*;
pub use ui_commands::UiCommand;
use crate::editor::Editor;
use crate::editor::{EDITOR, Editor};
use crate::error_handling::ResultPanicExplanation;
use crate::INITIAL_DIMENSIONS;
use handler::NeovimHandler;
lazy_static! {
pub static ref BRIDGE: Bridge = Bridge::new();
}
#[cfg(target_os = "windows")]
fn set_windows_creation_flags(cmd: &mut Command) {
cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW
@ -49,9 +54,9 @@ async fn drain(receiver: &mut UnboundedReceiver<UiCommand>) -> Option<Vec<UiComm
}
}
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)).await
async fn start_process(mut receiver: UnboundedReceiver<UiCommand>) {
let (width, height) = INITIAL_DIMENSIONS;
let (mut nvim, io_handler, _) = create::new_child_cmd(&mut create_nvim_command(), NeovimHandler { }).await
.unwrap_or_explained_panic("Could not create nvim process", "Could not locate or start the neovim process");
tokio::spawn(async move {
@ -96,19 +101,22 @@ pub struct Bridge {
}
impl Bridge {
pub fn new(editor: Arc<Mutex<Editor>>, grid_dimensions: (u64, u64)) -> Bridge {
pub fn new() -> Bridge {
let runtime = Runtime::new().unwrap();
let (sender, receiver) = unbounded_channel::<UiCommand>();
runtime.spawn(async move {
start_process(editor, receiver, grid_dimensions).await;
start_process(receiver).await;
});
println!("Bridge created.");
Bridge { _runtime: runtime, sender }
}
pub fn queue_command(&mut self, command: UiCommand) {
self.sender.send(command)
pub fn queue_command(&self, command: UiCommand) {
let mut sender = self.sender.clone();
sender.send(command)
.unwrap_or_explained_panic(
"Could Not Send UI Command",
"Could not send UI command from the window system to the neovim process.");

@ -2,7 +2,7 @@ mod cursor;
mod style;
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use skulpin::skia_safe::colors;
use skulpin::winit::window::Window;
@ -10,6 +10,12 @@ use skulpin::winit::window::Window;
pub use cursor::{Cursor, CursorShape, CursorMode};
pub use style::{Colors, Style};
use crate::bridge::{GridLineCell, GuiOption, RedrawEvent};
use crate::redraw_scheduler::REDRAW_SCHEDULER;
use crate::INITIAL_DIMENSIONS;
lazy_static! {
pub static ref EDITOR: Arc<Mutex<Editor>> = Arc::new(Mutex::new(Editor::new()));
}
pub type GridCell = Option<(char, Option<Style>)>;
@ -27,8 +33,6 @@ pub struct Editor {
pub dirty: Vec<Vec<bool>>,
pub should_clear: bool,
pub window: Option<Arc<Window>>,
pub title: String,
pub size: (u64, u64),
pub font_name: Option<String>,
@ -40,17 +44,15 @@ pub struct Editor {
}
impl Editor {
pub fn new(dimensions: (u64, u64)) -> Editor {
pub fn new() -> Editor {
let mut editor = Editor {
grid: Vec::new(),
dirty: Vec::new(),
should_clear: true,
window: None,
title: "Neovide".to_string(),
cursor: Cursor::new(),
size: dimensions,
size: INITIAL_DIMENSIONS,
font_name: None,
font_size: None,
default_colors: Colors::new(Some(colors::WHITE), Some(colors::BLACK), Some(colors::GREY)),
@ -70,7 +72,7 @@ impl Editor {
RedrawEvent::ModeChange { mode_index } => self.cursor.change_mode(mode_index, &self.defined_styles),
RedrawEvent::BusyStart => self.cursor.enabled = false,
RedrawEvent::BusyStop => self.cursor.enabled = true,
RedrawEvent::Flush => { self.window.as_ref().map(|window| window.request_redraw()); },
RedrawEvent::Flush => REDRAW_SCHEDULER.request_redraw(),
RedrawEvent::Resize { width, height, .. } => self.resize((width, height)),
RedrawEvent::DefaultColorsSet { colors } => self.default_colors = colors,
RedrawEvent::HighlightAttributesDefine { id, style } => { self.defined_styles.insert(id, style); },

@ -9,17 +9,16 @@ mod redraw_scheduler;
#[macro_use] extern crate derive_new;
#[macro_use] extern crate rust_embed;
#[macro_use] extern crate lazy_static;
use std::sync::{Arc, Mutex};
use lazy_static::initialize;
use bridge::BRIDGE;
use window::ui_loop;
use editor::Editor;
use bridge::Bridge;
const INITIAL_DIMENSIONS: (u64, u64) = (100, 50);
pub const INITIAL_DIMENSIONS: (u64, u64) = (100, 50);
fn main() {
let editor = Arc::new(Mutex::new(Editor::new(INITIAL_DIMENSIONS)));
let bridge = Bridge::new(editor.clone(), INITIAL_DIMENSIONS);
ui_loop(editor, bridge, INITIAL_DIMENSIONS);
initialize(&BRIDGE);
ui_loop();
}

@ -1,28 +1,48 @@
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use std::time::Instant;
use skulpin::winit::window::Window;
use tokio::runtime::Runtime;
use tokio::time::{Instant as TokioInstant, delay_until};
lazy_static! {
pub static ref REDRAW_SCHEDULER: RedrawScheduler = RedrawScheduler::new();
}
pub struct RedrawScheduler {
runtime: Runtime,
window: Arc<Window>
window: Mutex<Option<Arc<Window>>> // Swap to some atomic type
}
impl RedrawScheduler {
pub fn new(window: &Arc<Window>) -> RedrawScheduler {
pub fn new() -> RedrawScheduler {
RedrawScheduler {
runtime: Runtime::new().unwrap(),
window: window.clone()
window: Mutex::new(None)
}
}
pub fn schedule(&self, time: Instant) {
let window = self.window.clone();
self.runtime.spawn(async move {
delay_until(TokioInstant::from_std(time)).await;
let window = {
self.window.lock().unwrap().clone()
};
if let Some(window) = window {
self.runtime.spawn(async move {
delay_until(TokioInstant::from_std(time)).await;
window.request_redraw();
});
}
}
pub fn request_redraw(&self) {
if let Some(window) = self.window.lock().unwrap().as_ref() {
window.request_redraw();
});
}
}
pub fn set_window(&self, window: &Arc<Window>){
let mut window_ref = self.window.lock().unwrap();
window_ref.replace(window.clone());
}
}

@ -4,7 +4,7 @@ use std::time::{Duration, Instant};
use skulpin::skia_safe::{Canvas, Paint, Path, Point};
use crate::renderer::{CachingShaper, FontLookup};
use crate::editor::{Colors, Cursor, CursorShape, Editor};
use crate::editor::{EDITOR, Colors, Cursor, CursorShape, Editor};
const AVERAGE_MOTION_PERCENTAGE: f32 = 0.7;
const MOTION_PERCENTAGE_SPREAD: f32 = 0.5;
@ -171,13 +171,12 @@ impl CursorRenderer {
pub fn draw(&mut self,
cursor: Cursor, default_colors: &Colors,
font_width: f32, font_height: f32,
paint: &mut Paint, editor: Arc<Mutex<Editor>>,
shaper: &mut CachingShaper, fonts_lookup: &mut FontLookup,
canvas: &mut Canvas) -> (bool, Option<Instant>) {
paint: &mut Paint, shaper: &mut CachingShaper,
fonts_lookup: &mut FontLookup, canvas: &mut Canvas) -> (bool, Option<Instant>) {
let (render, scheduled_update) = self.blink_status.update_status(&cursor);
self.previous_position = {
let editor = editor.lock().unwrap();
let editor = EDITOR.lock().unwrap();
let (_, grid_y) = cursor.position;
let (_, previous_y) = self.previous_position;
let (_, height) = editor.size;
@ -227,7 +226,7 @@ impl CursorRenderer {
// Draw foreground
paint.set_color(cursor.foreground(&default_colors).to_color());
let editor = editor.lock().unwrap();
let editor = EDITOR.lock().unwrap();
let character = editor.grid[grid_y as usize][grid_x as usize].clone()
.map(|(character, _)| character)
.unwrap_or(' ');

@ -13,7 +13,7 @@ pub use caching_shaper::CachingShaper;
use cursor_renderer::CursorRenderer;
use fonts::FontLookup;
use crate::editor::{Editor, Style, Colors};
use crate::editor::{EDITOR, Editor, Style, Colors};
const DEFAULT_FONT_NAME: &str = "Delugia Nerd Font";
const DEFAULT_FONT_SIZE: f32 = 14.0;
@ -26,8 +26,6 @@ pub struct DrawResult {
}
pub struct Renderer {
editor: Arc<Mutex<Editor>>,
surface: Option<Surface>,
paint: Paint,
fonts_lookup: FontLookup,
@ -39,7 +37,7 @@ pub struct Renderer {
}
impl Renderer {
pub fn new(editor: Arc<Mutex<Editor>>) -> Renderer {
pub fn new() -> Renderer {
let surface = None;
let mut paint = Paint::new(colors::WHITE, None);
paint.set_anti_alias(false);
@ -50,7 +48,7 @@ impl Renderer {
let (font_width, font_height) = shaper.font_base_dimensions(&mut fonts_lookup);
let cursor_renderer = CursorRenderer::new();
Renderer { editor, surface, paint, fonts_lookup, shaper, font_width, font_height, cursor_renderer }
Renderer { surface, paint, fonts_lookup, shaper, font_width, font_height, cursor_renderer }
}
fn set_font(&mut self, name: &str, size: f32) {
@ -121,7 +119,7 @@ impl Renderer {
pub fn draw(&mut self, gpu_canvas: &mut Canvas, coordinate_system_helper: &CoordinateSystemHelper) -> DrawResult {
let ((draw_commands, should_clear), default_colors, cursor, font_name, font_size) = {
let mut editor = self.editor.lock().unwrap();
let mut editor = EDITOR.lock().unwrap();
(
editor.build_draw_commands(),
editor.default_colors.clone(),
@ -173,9 +171,8 @@ impl Renderer {
let (cursor_animating, scheduled_cursor_update) = self.cursor_renderer.draw(
cursor, &default_colors,
self.font_width, self.font_height,
&mut self.paint, self.editor.clone(),
&mut self.shaper, &mut self.fonts_lookup,
gpu_canvas);
&mut self.paint, &mut self.shaper,
&mut self.fonts_lookup, gpu_canvas);
DrawResult::new(draw_commands.len() > 0 || cursor_animating, font_changed, scheduled_cursor_update)
}

@ -7,12 +7,13 @@ use skulpin::skia_safe::icu;
use skulpin::winit::dpi::LogicalSize;
use skulpin::winit::event::{ElementState, Event, MouseScrollDelta, StartCause, WindowEvent};
use skulpin::winit::event_loop::{ControlFlow, EventLoop};
use skulpin::winit::window::{Icon, WindowBuilder};
use skulpin::winit::window::{Icon, Window, WindowBuilder};
use crate::editor::Editor;
use crate::bridge::{construct_keybinding_string, Bridge, UiCommand};
use crate::bridge::{construct_keybinding_string, BRIDGE, Bridge, UiCommand};
use crate::renderer::Renderer;
use crate::redraw_scheduler::RedrawScheduler;
use crate::redraw_scheduler::REDRAW_SCHEDULER;
use crate::error_handling::ResultPanicExplanation;
use crate::INITIAL_DIMENSIONS;
#[derive(RustEmbed)]
#[folder = "assets/"]
@ -20,20 +21,20 @@ struct Asset;
const EXTRA_LIVE_FRAMES: usize = 10;
fn handle_new_grid_size(new_size: LogicalSize, renderer: &Renderer, bridge: &mut Bridge) {
fn handle_new_grid_size(new_size: LogicalSize, renderer: &Renderer) {
if new_size.width > 0.0 && new_size.height > 0.0 {
let new_width = ((new_size.width + 1.0) as f32 / renderer.font_width) as u64;
let new_height = ((new_size.height + 1.0) as f32 / renderer.font_height) as u64;
// Add 1 here to make sure resizing doesn't change the grid size on startup
bridge.queue_command(UiCommand::Resize { width: new_width as i64, height: new_height as i64 });
BRIDGE.queue_command(UiCommand::Resize { width: new_width as i64, height: new_height as i64 });
}
}
pub fn ui_loop(editor: Arc<Mutex<Editor>>, mut bridge: Bridge, initial_size: (u64, u64)) {
let mut renderer = Renderer::new(editor.clone());
pub fn ui_loop() {
let event_loop = EventLoop::<()>::with_user_event();
let (width, height) = initial_size;
let mut renderer = Renderer::new();
let (width, height) = INITIAL_DIMENSIONS;
let logical_size = LogicalSize::new(
(width as f32 * renderer.font_width) as f64,
(height as f32 * renderer.font_height + 1.0) as f64
@ -57,6 +58,8 @@ pub fn ui_loop(editor: Arc<Mutex<Editor>>, mut bridge: Bridge, initial_size: (u6
.build(&event_loop)
.expect("Failed to create window"));
REDRAW_SCHEDULER.set_window(&window);
let mut skulpin_renderer = RendererBuilder::new()
.prefer_integrated_gpu()
.use_vulkan_debug_layer(true)
@ -65,17 +68,11 @@ pub fn ui_loop(editor: Arc<Mutex<Editor>>, mut bridge: Bridge, initial_size: (u6
.build(&window)
.expect("Failed to create renderer");
let mut mouse_down = false;
let mut mouse_pos = (0, 0);
icu::init();
{
let mut editor = editor.lock().unwrap();
editor.window = Some(window.clone());
}
let mut mouse_down = false;
let mut mouse_pos = (0, 0);
let redraw_scheduler = RedrawScheduler::new(&window);
let mut live_frames = 0;
let mut frame_start = Instant::now();
event_loop.run(move |event, _window_target, control_flow| {
@ -94,7 +91,7 @@ pub fn ui_loop(editor: Arc<Mutex<Editor>>, mut bridge: Bridge, initial_size: (u6
event: WindowEvent::Resized(new_size),
..
} => {
handle_new_grid_size(new_size, &renderer, &mut bridge)
handle_new_grid_size(window.inner_size(), &renderer)
},
Event::WindowEvent {
@ -106,7 +103,7 @@ pub fn ui_loop(editor: Arc<Mutex<Editor>>, mut bridge: Bridge, initial_size: (u6
} => {
construct_keybinding_string(input)
.map(UiCommand::Keyboard)
.map(|keybinding_string| bridge.queue_command(keybinding_string));
.map(|keybinding_string| BRIDGE.queue_command(keybinding_string));
},
Event::WindowEvent {
@ -120,7 +117,7 @@ pub fn ui_loop(editor: Arc<Mutex<Editor>>, mut bridge: Bridge, initial_size: (u6
let grid_x = (position.y as f32 / renderer.font_height) as i64;
mouse_pos = (grid_x, grid_y);
if mouse_down {
bridge.queue_command(UiCommand::Drag(grid_x, grid_y));
BRIDGE.queue_command(UiCommand::Drag(grid_x, grid_y));
}
}
@ -142,7 +139,7 @@ pub fn ui_loop(editor: Arc<Mutex<Editor>>, mut bridge: Bridge, initial_size: (u6
}
};
let (grid_x, grid_y) = mouse_pos;
bridge.queue_command(UiCommand::MouseButton { action: input_type.to_string(), position: (grid_x, grid_y) });
BRIDGE.queue_command(UiCommand::MouseButton { action: input_type.to_string(), position: (grid_x, grid_y) });
}
Event::WindowEvent {
@ -161,7 +158,7 @@ pub fn ui_loop(editor: Arc<Mutex<Editor>>, mut bridge: Bridge, initial_size: (u6
};
if let Some(input_type) = vertical_input_type {
bridge.queue_command(UiCommand::Scroll { direction: input_type.to_string(), position: mouse_pos });
BRIDGE.queue_command(UiCommand::Scroll { direction: input_type.to_string(), position: mouse_pos });
}
let horizontal_input_type = if horizontal > 0.0 {
@ -173,13 +170,13 @@ pub fn ui_loop(editor: Arc<Mutex<Editor>>, mut bridge: Bridge, initial_size: (u6
};
if let Some(input_type) = horizontal_input_type {
bridge.queue_command(UiCommand::Scroll { direction: input_type.to_string(), position: mouse_pos });
BRIDGE.queue_command(UiCommand::Scroll { direction: input_type.to_string(), position: mouse_pos });
}
}
Event::RedrawRequested { .. } => {
frame_start = Instant::now();
if let Err(e) = skulpin_renderer.draw(&window.clone(), |canvas, coordinate_system_helper| {
if let Err(e) = skulpin_renderer.draw(&window, |canvas, coordinate_system_helper| {
let draw_result = renderer.draw(canvas, coordinate_system_helper);
if draw_result.is_animating {
live_frames = EXTRA_LIVE_FRAMES;
@ -190,7 +187,7 @@ pub fn ui_loop(editor: Arc<Mutex<Editor>>, mut bridge: Bridge, initial_size: (u6
}
if draw_result.font_changed {
handle_new_grid_size(window.inner_size(), &renderer, &mut bridge)
handle_new_grid_size(window.inner_size(), &renderer)
}
if live_frames > 0 {
@ -200,7 +197,7 @@ pub fn ui_loop(editor: Arc<Mutex<Editor>>, mut bridge: Bridge, initial_size: (u6
}
if let Some(scheduled_update) = draw_result.scheduled_update {
redraw_scheduler.schedule(scheduled_update);
REDRAW_SCHEDULER.schedule(scheduled_update);
}
}) {
println!("Error during draw: {:?}", e);

Loading…
Cancel
Save