WIP for structured settings system

macos-click-through
Jon Valdés 5 years ago
parent ff67afaa46
commit e296e2a4ce

@ -20,6 +20,9 @@ use window::ui_loop;
pub const INITIAL_DIMENSIONS: (u64, u64) = (100, 50); pub const INITIAL_DIMENSIONS: (u64, u64) = (100, 50);
fn main() { fn main() {
window::initialize_settings();
redraw_scheduler::initialize_settings();
initialize(&BRIDGE); initialize(&BRIDGE);
ui_loop(); ui_loop();
} }

@ -4,12 +4,41 @@ use std::time::Instant;
use log::trace; use log::trace;
use crate::settings::SETTINGS; use crate::settings::{SETTINGS, Value};
lazy_static! { lazy_static! {
pub static ref REDRAW_SCHEDULER: RedrawScheduler = RedrawScheduler::new(); 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>) -> Value {
match name {
"extra_buffer_frames" => {
let mut settings = SETTINGS.get::<RedrawSettings>();
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 { pub struct RedrawScheduler {
frames_queued: AtomicU16, frames_queued: AtomicU16,
scheduled_frame: Mutex<Option<Instant>> scheduled_frame: Mutex<Option<Instant>>
@ -37,8 +66,8 @@ impl RedrawScheduler {
pub fn queue_next_frame(&self) { pub fn queue_next_frame(&self) {
trace!("Next frame queued"); trace!("Next frame queued");
let buffer_frames = SETTINGS.get("extra_buffer_frames").read_u16(); let buffer_frames = SETTINGS.get::<RedrawSettings>().extra_buffer_frames;
self.frames_queued.store(buffer_frames, Ordering::Relaxed); self.frames_queued.store(buffer_frames as u16, Ordering::Relaxed);
} }
pub fn should_draw(&self) -> bool { pub fn should_draw(&self) -> bool {

@ -1,12 +1,13 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryInto; use std::convert::TryInto;
use std::any::{Any, TypeId};
use rmpv::Value; pub use rmpv::Value;
use nvim_rs::Neovim; use nvim_rs::Neovim;
use nvim_rs::compat::tokio::Compat; use nvim_rs::compat::tokio::Compat;
use flexi_logger::{Logger, Criterion, Naming, Cleanup}; use flexi_logger::{Logger, Criterion, Naming, Cleanup};
use tokio::process::ChildStdin; use tokio::process::ChildStdin;
use parking_lot::Mutex; use parking_lot::RwLock;
use log::warn; use log::warn;
use crate::error_handling::ResultPanicExplanation; use crate::error_handling::ResultPanicExplanation;
@ -15,120 +16,86 @@ lazy_static! {
pub static ref SETTINGS: Settings = Settings::new(); pub static ref SETTINGS: Settings = Settings::new();
} }
#[derive(Debug)] struct SettingsObject {
pub enum Setting { object: Box<dyn Any + Send + Sync>,
Bool(bool),
U16(u16),
String(String)
} }
impl Setting { pub struct Settings {
fn new_bool(value: bool) -> Setting { pub neovim_arguments: Vec<String>,
Setting::Bool(value) settings: RwLock<HashMap<TypeId, SettingsObject>>,
} listeners: RwLock<HashMap<String, fn (&str, Option<Value>)->Value>>,
}
pub fn read_bool(&self) -> bool { impl Settings {
if let Setting::Bool(value) = self {
*value
} else {
panic!("Could not read setting as bool");
}
}
fn new_u16(value: u16) -> Setting { fn new() -> Settings {
Setting::U16(value)
} let mut no_idle = false;
let mut buffer_frames = 1;
pub fn read_u16(&self) -> u16 { let neovim_arguments = std::env::args().filter(|arg| {
if let Setting::U16(value) = self { if arg == "--log" {
*value 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 { } else {
panic!("Could not read setting as u16"); true
}
} }
}).collect::<Vec<String>>();
fn new_string(value: String) -> Setting {
Setting::String(value)
}
pub fn read_string(&self) -> String { Settings{
if let Setting::String(value) = self { neovim_arguments,
value.clone() settings: RwLock::new(HashMap::new()),
} else { listeners: RwLock::new(HashMap::new()),
panic!("Could not read setting as string");
} }
} }
fn parse(&mut self, value: Value) { pub fn add_listener(&self, property_name: &str, func: fn (&str, Option<Value>)-> Value) {
match self { self.listeners.write().insert(String::from(property_name), func);
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;
}
}
}
} }
fn unparse(&self) -> Value { pub fn set<T: Clone + Send + Sync + 'static >(&self, t: &T) {
match self { let type_id : TypeId = TypeId::of::<T>();
Setting::Bool(internal_bool) => { let t : T = (*t).clone();
let value = if *internal_bool { self.settings.write().insert(type_id, SettingsObject{ object: Box::new(t)});
1
} else {
0
};
Value::from(value)
},
Setting::U16(internal_u16) => Value::from(*internal_u16),
Setting::String(internal_string) => Value::from(internal_string.as_str()),
}
} }
fn clone(&self) -> Setting { pub fn get<'a, T: Clone + Send + Sync + 'static>(&'a self) -> T {
match self { let read_lock = self.settings.read();
Setting::Bool(_) => Setting::new_bool(self.read_bool()), let boxed = &read_lock.get(&TypeId::of::<T>()).expect("Trying to retrieve a settings object that doesn't exist");
Setting::U16(_) => Setting::new_u16(self.read_u16()), let value: &T = boxed.object.downcast_ref::<T>().expect("Attempted to extract a settings object of the wrong type");
Setting::String(_) => Setting::new_string(self.read_string()), (*value).clone()
}
} }
}
pub struct Settings {
pub neovim_arguments: Vec<String>,
pub settings: Mutex<HashMap<String, Setting>>
}
impl Settings {
pub async fn read_initial_values(&self, nvim: &Neovim<Compat<ChildStdin>>) { pub async fn read_initial_values(&self, nvim: &Neovim<Compat<ChildStdin>>) {
let keys : Vec<String> = self.settings.lock().keys().cloned().collect(); let keys : Vec<String> = self.listeners.read().keys().cloned().collect();
for name in keys { for name in keys {
let variable_name = format!("neovide_{}", name.to_string()); let variable_name = format!("neovide_{}", name.to_string());
match nvim.get_var(&variable_name).await { 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) => { Err(error) => {
warn!("Initial value load failed for {}: {}", name, error); warn!("Initial value load failed for {}: {}", name, error);
let setting = self.get(&name); let setting = self.listeners.read().get(&name).unwrap()(&name, None);
nvim.set_var(&variable_name, setting.unparse()).await.ok(); nvim.set_var(&variable_name, setting).await.ok();
} }
} }
} }
} }
pub async fn setup_changed_listeners(&self, nvim: &Neovim<Compat<ChildStdin>>) { pub async fn setup_changed_listeners(&self, nvim: &Neovim<Compat<ChildStdin>>) {
let keys : Vec<String> = self.settings.lock().keys().cloned().collect(); let keys : Vec<String> = self.listeners.read().keys().cloned().collect();
for name in keys { for name in keys {
let vimscript = format!( let vimscript = format!(
concat!( concat!(
@ -151,15 +118,10 @@ impl Settings {
let name: Result<String, _>= name.try_into(); let name: Result<String, _>= name.try_into();
let name = name.unwrap(); let name = name.unwrap();
self.settings.lock().get_mut(&name).unwrap().parse(value); self.listeners.read().get(&name).unwrap()(&name, Some(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()
} }
/*
pub fn new() -> Settings { pub fn new() -> Settings {
let mut no_idle = false; let mut no_idle = false;
let mut buffer_frames = 1; let mut buffer_frames = 1;
@ -191,4 +153,5 @@ impl Settings {
Settings { neovim_arguments, settings: Mutex::new(settings) } Settings { neovim_arguments, settings: Mutex::new(settings) }
} }
*/
} }

@ -14,7 +14,7 @@ use crate::bridge::{parse_keycode, append_modifiers, BRIDGE, UiCommand};
use crate::renderer::Renderer; use crate::renderer::Renderer;
use crate::redraw_scheduler::REDRAW_SCHEDULER; use crate::redraw_scheduler::REDRAW_SCHEDULER;
use crate::editor::EDITOR; use crate::editor::EDITOR;
use crate::settings::SETTINGS; use crate::settings::{SETTINGS, Value};
use crate::INITIAL_DIMENSIONS; use crate::INITIAL_DIMENSIONS;
#[derive(RustEmbed)] #[derive(RustEmbed)]
@ -236,7 +236,7 @@ impl WindowWrapper {
} }
debug!("Render Triggered"); debug!("Render Triggered");
if REDRAW_SCHEDULER.should_draw() || SETTINGS.get("no_idle").read_bool() { if REDRAW_SCHEDULER.should_draw() || SETTINGS.get::<WindowSettings>().no_idle {
let renderer = &mut self.renderer; let renderer = &mut self.renderer;
if self.skulpin_renderer.draw(&self.window, |canvas, coordinate_system_helper| { if self.skulpin_renderer.draw(&self.window, |canvas, coordinate_system_helper| {
if renderer.draw(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>) -> Value {
let mut settings = SETTINGS.get::<WindowSettings>();
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() { pub fn ui_loop() {
let mut window = WindowWrapper::new(); let mut window = WindowWrapper::new();
@ -280,7 +319,7 @@ pub fn ui_loop() {
} }
let elapsed = frame_start.elapsed(); let elapsed = frame_start.elapsed();
let refresh_rate = SETTINGS.get("refresh_rate").read_u16() as f32; let refresh_rate = SETTINGS.get::<WindowSettings>().refresh_rate as f32;
let frame_length = Duration::from_secs_f32(1.0 / refresh_rate); let frame_length = Duration::from_secs_f32(1.0 / refresh_rate);
if elapsed < frame_length { if elapsed < frame_length {
sleep(frame_length - elapsed); sleep(frame_length - elapsed);

Loading…
Cancel
Save