diff --git a/src/bridge/mod.rs b/src/bridge/mod.rs index 1f7b755..df5a2ad 100644 --- a/src/bridge/mod.rs +++ b/src/bridge/mod.rs @@ -15,10 +15,10 @@ use log::{info, error, trace}; pub use events::*; pub use keybindings::*; +use crate::settings::*; pub use ui_commands::UiCommand; use handler::NeovimHandler; use crate::error_handling::ResultPanicExplanation; -use crate::settings::SETTINGS; use crate::INITIAL_DIMENSIONS; diff --git a/src/main.rs b/src/main.rs index c020471..bcfa176 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,15 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +#[macro_use] +mod settings; + mod bridge; mod editor; mod window; mod renderer; mod error_handling; mod redraw_scheduler; -mod settings; + #[macro_use] extern crate derive_new; #[macro_use] extern crate rust_embed; diff --git a/src/redraw_scheduler.rs b/src/redraw_scheduler.rs index 5665398..9780542 100644 --- a/src/redraw_scheduler.rs +++ b/src/redraw_scheduler.rs @@ -4,7 +4,7 @@ use std::time::Instant; use log::trace; -use crate::settings::{SETTINGS, Value}; +use crate::settings::*; lazy_static! { pub static ref REDRAW_SCHEDULER: RedrawScheduler = RedrawScheduler::new(); @@ -15,28 +15,13 @@ 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); + register_nvim_setting!("extra_buffer_frames", RedrawSettings::extra_buffer_frames); } pub struct RedrawScheduler { diff --git a/src/settings.rs b/src/settings.rs index f09c113..aa7d059 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -16,6 +16,85 @@ lazy_static! { pub static ref SETTINGS: Settings = Settings::new(); } +pub trait FromValue { + fn from_value(&mut self, value: Value); +} + +impl FromValue for f32 { + fn from_value(&mut self, value: Value) { + // TODO -- Warn when incorrect type + if value.is_f32() { + *self = value.as_f64().unwrap() as f32; + } + } +} + +impl FromValue for u64 { + fn from_value(&mut self, value: Value) { + // TODO -- Warn when incorrect type + if value.is_u64() { + *self = value.as_u64().unwrap(); + } + } +} + +impl FromValue for u32 { + fn from_value(&mut self, value: Value) { + // TODO -- Warn when incorrect type + if value.is_u64() { + *self = value.as_u64().unwrap() as u32; + } + } +} + +impl FromValue for i32 { + fn from_value(&mut self, value: Value) { + // TODO -- Warn when incorrect type + if value.is_i64() { + *self = value.as_i64().unwrap() as i32; + } + } +} + +impl FromValue for String { + fn from_value(&mut self, value: Value) { + // TODO -- Warn when incorrect type + if value.is_str() { + *self = String::from(value.as_str().unwrap()); + } + } +} + +impl FromValue for bool { + fn from_value(&mut self, value: Value) { + // TODO -- Warn when incorrect type + if value.is_bool() { + *self = value.as_bool().unwrap(); + } + } +} + +#[macro_export] +macro_rules! register_nvim_setting { + ($vim_setting_name: expr, $type_name:ident :: $field_name: ident) => {{ + fn update_func(value: Value) { + let mut s = SETTINGS.get::<$type_name>(); + s.$field_name.from_value(value); + SETTINGS.set(&s); + } + + fn reader_func() -> Value { + let s = SETTINGS.get::<$type_name>(); + s.$field_name.into() + } + + SETTINGS.add_handlers($vim_setting_name, update_func, reader_func); + }}; +} + +type UpdateHandlerFunc = fn(Value); +type ReaderFunc = fn()->Value; + struct SettingsObject { object: Box, } @@ -23,7 +102,8 @@ struct SettingsObject { pub struct Settings { pub neovim_arguments: Vec, settings: RwLock>, - listeners: RwLock)->Value>>, + listeners: RwLock>, + readers: RwLock>, } impl Settings { @@ -33,6 +113,8 @@ impl Settings { let mut no_idle = false; let mut buffer_frames = 1; + // TODO -- Make command line parsing work again + let neovim_arguments = std::env::args().filter(|arg| { if arg == "--log" { Logger::with_str("neovide") @@ -57,11 +139,13 @@ impl Settings { neovim_arguments, settings: RwLock::new(HashMap::new()), listeners: RwLock::new(HashMap::new()), + readers: RwLock::new(HashMap::new()), } } - pub fn add_listener(&self, property_name: &str, func: fn (&str, Option)-> Value) { - self.listeners.write().insert(String::from(property_name), func); + pub fn add_handlers(&self, property_name: &str, update_func: UpdateHandlerFunc, reader_func: ReaderFunc) { + self.listeners.write().insert(String::from(property_name), update_func); + self.readers.write().insert(String::from(property_name), reader_func); } pub fn set(&self, t: &T) { @@ -83,11 +167,11 @@ impl Settings { let variable_name = format!("neovide_{}", name.to_string()); match nvim.get_var(&variable_name).await { Ok(value) => { - self.listeners.read().get(&name).unwrap()(&name, Some(value)); + self.listeners.read().get(&name).unwrap()(value); }, Err(error) => { warn!("Initial value load failed for {}: {}", name, error); - let setting = self.listeners.read().get(&name).unwrap()(&name, None); + let setting = self.readers.read().get(&name).unwrap()(); nvim.set_var(&variable_name, setting).await.ok(); } } @@ -118,40 +202,6 @@ impl Settings { let name: Result= name.try_into(); let name = name.unwrap(); - self.listeners.read().get(&name).unwrap()(&name, Some(value)); - } - - /* - pub fn new() -> Settings { - let mut no_idle = false; - let mut buffer_frames = 1; - - 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::>(); - - let mut settings = HashMap::new(); - - settings.insert("no_idle".to_string(), Setting::new_bool(no_idle)); - settings.insert("extra_buffer_frames".to_string(), Setting::new_u16(buffer_frames)); - settings.insert("refresh_rate".to_string(), Setting::new_u16(60)); - - Settings { neovim_arguments, settings: Mutex::new(settings) } + self.listeners.read().get(&name).unwrap()(value); } - */ } diff --git a/src/window.rs b/src/window.rs index bbdc269..33a263a 100644 --- a/src/window.rs +++ b/src/window.rs @@ -10,11 +10,11 @@ use skulpin::sdl2::event::Event; use skulpin::sdl2::keyboard::{Mod, Keycode}; use skulpin::{RendererBuilder, Renderer as SkulpinRenderer, PresentMode, CoordinateSystem, dpis}; +use crate::settings::*; 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, Value}; use crate::INITIAL_DIMENSIONS; #[derive(RustEmbed)] @@ -257,37 +257,14 @@ struct WindowSettings { 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); + + register_nvim_setting!("refresh_rate", WindowSettings::refresh_rate); + register_nvim_setting!("no_idle", WindowSettings::no_idle); } pub fn ui_loop() {