diff --git a/src/main.rs b/src/main.rs index 80e1332..c020471 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,9 @@ use window::ui_loop; pub const INITIAL_DIMENSIONS: (u64, u64) = (100, 50); fn main() { + window::initialize_settings(); + redraw_scheduler::initialize_settings(); + initialize(&BRIDGE); ui_loop(); } diff --git a/src/redraw_scheduler.rs b/src/redraw_scheduler.rs index a6545dc..57f13e7 100644 --- a/src/redraw_scheduler.rs +++ b/src/redraw_scheduler.rs @@ -4,12 +4,41 @@ use std::time::Instant; use log::trace; -use crate::settings::SETTINGS; +use crate::settings::{SETTINGS, Value}; lazy_static! { pub static ref REDRAW_SCHEDULER: RedrawScheduler = RedrawScheduler::new(); } +#[derive(Clone)] +struct RedrawSettings { + extra_buffer_frames: u64, +} + +fn parse_changed_setting(name: &str, value: Option) -> Value { + match name { + "extra_buffer_frames" => { + let mut settings = SETTINGS.get::(); + if let Some(value) = value { + settings.extra_buffer_frames= value.as_u64().unwrap(); // TODO -- handle wrong data type + SETTINGS.set(&settings); + } + Value::from(settings.extra_buffer_frames) + } + _ => { + panic!(format!("Unknown setting: {}", name)); + } + } +} + +pub fn initialize_settings() { + SETTINGS.set(&RedrawSettings { extra_buffer_frames: 60 }); + + SETTINGS.add_listener("extra_buffer_frames", parse_changed_setting); +} + + + pub struct RedrawScheduler { frames_queued: AtomicU16, scheduled_frame: Mutex> @@ -37,8 +66,8 @@ impl RedrawScheduler { pub fn queue_next_frame(&self) { trace!("Next frame queued"); - let buffer_frames = SETTINGS.get("extra_buffer_frames").read_u16(); - self.frames_queued.store(buffer_frames, Ordering::Relaxed); + let buffer_frames = SETTINGS.get::().extra_buffer_frames; + self.frames_queued.store(buffer_frames as u16, Ordering::Relaxed); } pub fn should_draw(&self) -> bool { diff --git a/src/settings.rs b/src/settings.rs index 08a6bdb..f09c113 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,12 +1,13 @@ use std::collections::HashMap; use std::convert::TryInto; +use std::any::{Any, TypeId}; -use rmpv::Value; +pub use rmpv::Value; use nvim_rs::Neovim; use nvim_rs::compat::tokio::Compat; use flexi_logger::{Logger, Criterion, Naming, Cleanup}; use tokio::process::ChildStdin; -use parking_lot::Mutex; +use parking_lot::RwLock; use log::warn; use crate::error_handling::ResultPanicExplanation; @@ -15,120 +16,86 @@ lazy_static! { pub static ref SETTINGS: Settings = Settings::new(); } -#[derive(Debug)] -pub enum Setting { - Bool(bool), - U16(u16), - String(String) +struct SettingsObject { + object: Box, } -impl Setting { - fn new_bool(value: bool) -> Setting { - Setting::Bool(value) - } - - pub fn read_bool(&self) -> bool { - if let Setting::Bool(value) = self { - *value - } else { - panic!("Could not read setting as bool"); - } - } +pub struct Settings { + pub neovim_arguments: Vec, + settings: RwLock>, + listeners: RwLock)->Value>>, +} - fn new_u16(value: u16) -> Setting { - Setting::U16(value) - } +impl Settings { - pub fn read_u16(&self) -> u16 { - if let Setting::U16(value) = self { - *value - } else { - panic!("Could not read setting as u16"); - } - } - - fn new_string(value: String) -> Setting { - Setting::String(value) - } + fn new() -> Settings { - pub fn read_string(&self) -> String { - if let Setting::String(value) = self { - value.clone() - } else { - panic!("Could not read setting as string"); - } - } + let mut no_idle = false; + let mut buffer_frames = 1; - fn parse(&mut self, value: Value) { - match self { - Setting::Bool(internal_bool) => { - if let Ok(value) = value.try_into() { - let intermediate: u64 = value; - *internal_bool = intermediate != 0; - } - }, - Setting::U16(internal_u16) => { - if let Ok(value) = value.try_into() { - let intermediate: u64 = value; - *internal_u16 = intermediate as u16; - } - }, - Setting::String(internal_string) => { - if let Ok(value) = value.try_into() { - let intermediate: String = value; - *internal_string = intermediate; - } + let neovim_arguments = std::env::args().filter(|arg| { + if arg == "--log" { + Logger::with_str("neovide") + .log_to_file() + .rotate(Criterion::Size(10_000_000), Naming::Timestamps, Cleanup::KeepLogFiles(1)) + .start() + .expect("Could not start logger"); + false + } else if arg == "--noIdle" { + no_idle = true; + false + } else if arg == "--extraBufferFrames" { + buffer_frames = 60; + false + } else { + true } - } - } + }).collect::>(); - fn unparse(&self) -> Value { - match self { - Setting::Bool(internal_bool) => { - let value = if *internal_bool { - 1 - } else { - 0 - }; - Value::from(value) - }, - Setting::U16(internal_u16) => Value::from(*internal_u16), - Setting::String(internal_string) => Value::from(internal_string.as_str()), + + Settings{ + neovim_arguments, + settings: RwLock::new(HashMap::new()), + listeners: RwLock::new(HashMap::new()), } } - fn clone(&self) -> Setting { - match self { - Setting::Bool(_) => Setting::new_bool(self.read_bool()), - Setting::U16(_) => Setting::new_u16(self.read_u16()), - Setting::String(_) => Setting::new_string(self.read_string()), - } + pub fn add_listener(&self, property_name: &str, func: fn (&str, Option)-> Value) { + self.listeners.write().insert(String::from(property_name), func); + } + + pub fn set(&self, t: &T) { + let type_id : TypeId = TypeId::of::(); + let t : T = (*t).clone(); + self.settings.write().insert(type_id, SettingsObject{ object: Box::new(t)}); } -} -pub struct Settings { - pub neovim_arguments: Vec, - pub settings: Mutex> -} + pub fn get<'a, T: Clone + Send + Sync + 'static>(&'a self) -> T { + let read_lock = self.settings.read(); + let boxed = &read_lock.get(&TypeId::of::()).expect("Trying to retrieve a settings object that doesn't exist"); + let value: &T = boxed.object.downcast_ref::().expect("Attempted to extract a settings object of the wrong type"); + (*value).clone() + } -impl Settings { pub async fn read_initial_values(&self, nvim: &Neovim>) { - let keys : Vec = self.settings.lock().keys().cloned().collect(); + let keys : Vec = self.listeners.read().keys().cloned().collect(); for name in keys { let variable_name = format!("neovide_{}", name.to_string()); match nvim.get_var(&variable_name).await { - Ok(value) => self.settings.lock().get_mut(&name).unwrap().parse(value), + Ok(value) => { + self.listeners.read().get(&name).unwrap()(&name, Some(value)); + }, Err(error) => { warn!("Initial value load failed for {}: {}", name, error); - let setting = self.get(&name); - nvim.set_var(&variable_name, setting.unparse()).await.ok(); + let setting = self.listeners.read().get(&name).unwrap()(&name, None); + nvim.set_var(&variable_name, setting).await.ok(); } } } } pub async fn setup_changed_listeners(&self, nvim: &Neovim>) { - let keys : Vec = self.settings.lock().keys().cloned().collect(); + let keys : Vec = self.listeners.read().keys().cloned().collect(); for name in keys { let vimscript = format!( concat!( @@ -151,15 +118,10 @@ impl Settings { let name: Result= name.try_into(); let name = name.unwrap(); - self.settings.lock().get_mut(&name).unwrap().parse(value); - } - - pub fn get(&self, name: &str) -> Setting { - let settings = self.settings.lock(); - let setting = settings.get(name).expect(&format!("Could not find option {}", name)); - setting.clone() + self.listeners.read().get(&name).unwrap()(&name, Some(value)); } + /* pub fn new() -> Settings { let mut no_idle = false; let mut buffer_frames = 1; @@ -191,4 +153,5 @@ impl Settings { Settings { neovim_arguments, settings: Mutex::new(settings) } } + */ } diff --git a/src/window.rs b/src/window.rs index da5e14b..bbdc269 100644 --- a/src/window.rs +++ b/src/window.rs @@ -14,7 +14,7 @@ use crate::bridge::{parse_keycode, append_modifiers, BRIDGE, UiCommand}; use crate::renderer::Renderer; use crate::redraw_scheduler::REDRAW_SCHEDULER; use crate::editor::EDITOR; -use crate::settings::SETTINGS; +use crate::settings::{SETTINGS, Value}; use crate::INITIAL_DIMENSIONS; #[derive(RustEmbed)] @@ -236,7 +236,7 @@ impl WindowWrapper { } debug!("Render Triggered"); - if REDRAW_SCHEDULER.should_draw() || SETTINGS.get("no_idle").read_bool() { + if REDRAW_SCHEDULER.should_draw() || SETTINGS.get::().no_idle { let renderer = &mut self.renderer; if self.skulpin_renderer.draw(&self.window, |canvas, coordinate_system_helper| { if renderer.draw(canvas, coordinate_system_helper) { @@ -251,6 +251,45 @@ impl WindowWrapper { } } +#[derive(Clone)] +struct WindowSettings { + refresh_rate: u64, + no_idle: bool, +} + +fn parse_changed_setting(name: &str, value: Option) -> Value { + let mut settings = SETTINGS.get::(); + match name { + "refresh_rate" => { + if let Some(value) = value { + settings.refresh_rate = value.as_u64().unwrap(); // TODO -- handle wrong data type + SETTINGS.set(&settings); + } + Value::from(settings.refresh_rate) + }, + "no_idle" => { + if let Some(value) = value { + settings.no_idle = value.as_bool().unwrap(); // TODO -- handle wrong data type + SETTINGS.set(&settings); + } + Value::from(settings.no_idle) + }, + _ => { + panic!(format!("Unknown setting: {}", name)); + } + } +} + +pub fn initialize_settings() { + SETTINGS.set(&WindowSettings { + refresh_rate: 60, + no_idle: false, + }); + + SETTINGS.add_listener("refresh_rate", parse_changed_setting); + SETTINGS.add_listener("no_idle", parse_changed_setting); +} + pub fn ui_loop() { let mut window = WindowWrapper::new(); @@ -280,7 +319,7 @@ pub fn ui_loop() { } let elapsed = frame_start.elapsed(); - let refresh_rate = SETTINGS.get("refresh_rate").read_u16() as f32; + let refresh_rate = SETTINGS.get::().refresh_rate as f32; let frame_length = Duration::from_secs_f32(1.0 / refresh_rate); if elapsed < frame_length { sleep(frame_length - elapsed);