Settings derive macro (#439)

* Added procedural macro crate

* Initial derive macro implementation

* Compiles for cursor settings

* Derive macro working correctly

* Derive macro working for all settings structs

* Cleanup

* Moved the binary back to the project root

* remove unused utils file

Co-authored-by: Tim Harding <Tim@TimHarding.co>
macos-click-through
Keith Simmons 4 years ago committed by GitHub
parent 33f6a4b914
commit af93c54f3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

9
Cargo.lock generated

@ -1505,6 +1505,7 @@ dependencies = [
"log", "log",
"lru", "lru",
"mockall", "mockall",
"neovide-derive",
"nvim-rs", "nvim-rs",
"parking_lot", "parking_lot",
"rand", "rand",
@ -1521,6 +1522,14 @@ dependencies = [
"winres", "winres",
] ]
[[package]]
name = "neovide-derive"
version = "0.1.0"
dependencies = [
"quote 1.0.7",
"syn 1.0.54",
]
[[package]] [[package]]
name = "net2" name = "net2"
version = "0.2.37" version = "0.2.37"

@ -6,6 +6,11 @@ edition = "2018"
build = "build.rs" build = "build.rs"
description = "A simple GUI for Neovim." description = "A simple GUI for Neovim."
[workspace]
members = [
"neovide-derive"
]
[features] [features]
default = ["sdl2"] default = ["sdl2"]
embed-fonts = [] embed-fonts = []
@ -13,6 +18,7 @@ sdl2 = ["skulpin/skulpin_sdl2"]
winit = ["skulpin/skulpin_winit"] winit = ["skulpin/skulpin_winit"]
[dependencies] [dependencies]
neovide-derive = { path = "neovide-derive" }
euclid = "0.20.7" euclid = "0.20.7"
font-kit = "0.10.0" font-kit = "0.10.0"
skribo = { git = "https://github.com/linebender/skribo" } skribo = { git = "https://github.com/linebender/skribo" }

@ -0,0 +1,11 @@
[package]
name = "neovide-derive"
version = "0.1.0"
edition = "2018"
[lib]
proc-macro = true
[dependencies]
syn = "1.0"
quote = "1.0"

@ -0,0 +1,77 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Attribute, Data, DataStruct, DeriveInput, Error, Ident, Lit, Meta};
#[proc_macro_derive(SettingGroup, attributes(setting_prefix))]
pub fn setting_group(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as DeriveInput);
let prefix = setting_prefix(input.attrs.as_ref())
.map(|p| format!("{}_", p))
.unwrap_or("".to_string());
stream(input, prefix)
}
fn stream(input: DeriveInput, prefix: String) -> TokenStream {
const ERR_MSG: &'static str = "Derive macro expects a struct";
match input.data {
Data::Struct(ref data) => struct_stream(input.ident, prefix, data),
Data::Enum(data) => Error::new_spanned(data.enum_token, ERR_MSG)
.to_compile_error()
.into(),
Data::Union(data) => Error::new_spanned(data.union_token, ERR_MSG)
.to_compile_error()
.into(),
}
}
fn struct_stream(name: Ident, prefix: String, data: &DataStruct) -> TokenStream {
let fragments = data.fields.iter().map(|field| match field.ident {
Some(ref ident) => {
let vim_setting_name = format!("{}{}", prefix, ident);
quote! {{
fn update_func(value: rmpv::Value) {
let mut s = crate::settings::SETTINGS.get::<#name>();
s.#ident.from_value(value);
crate::settings::SETTINGS.set(&s);
}
fn reader_func() -> rmpv::Value {
let s = crate::settings::SETTINGS.get::<#name>();
s.#ident.into()
}
crate::settings::SETTINGS.set_setting_handlers(
#vim_setting_name,
update_func,
reader_func
);
}}
}
None => {
Error::new_spanned(field.colon_token, "Expected named struct fields").to_compile_error()
}
});
let expanded = quote! {
impl #name {
pub fn register() {
let s: Self = Default::default();
crate::settings::SETTINGS.set(&s);
#(#fragments)*
}
}
};
TokenStream::from(expanded)
}
fn setting_prefix(attrs: &[Attribute]) -> Option<String> {
for attr in attrs.iter() {
if let Ok(Meta::NameValue(name_value)) = attr.parse_meta() {
if name_value.path.is_ident("setting_prefix") {
if let Lit::Str(literal) = name_value.lit {
return Some(literal.value());
}
}
}
}
None
}

@ -1,13 +1,14 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
#[macro_use] #[macro_use]
mod settings; extern crate neovide_derive;
mod bridge; mod bridge;
mod editor; mod editor;
mod error_handling; mod error_handling;
mod redraw_scheduler; mod redraw_scheduler;
mod renderer; mod renderer;
mod settings;
mod window; mod window;
#[macro_use] #[macro_use]
@ -17,18 +18,17 @@ extern crate rust_embed;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
use std::process; use std::{
use std::sync::atomic::AtomicBool; process,
use std::sync::mpsc::channel; sync::{atomic::AtomicBool, mpsc::channel, Arc},
use std::sync::Arc; };
use crossfire::mpsc::unbounded_future; use crossfire::mpsc::unbounded_future;
use window::window_geometry;
use bridge::start_bridge; use bridge::start_bridge;
use editor::start_editor; use editor::start_editor;
use window::create_window; use renderer::{cursor_renderer::CursorSettings, RendererSettings};
use window::{create_window, window_geometry, KeyboardSettings, WindowSettings};
pub const INITIAL_DIMENSIONS: (u64, u64) = (100, 50); pub const INITIAL_DIMENSIONS: (u64, u64) = (100, 50);
@ -139,10 +139,11 @@ fn main() {
} }
} }
window::initialize_settings(); KeyboardSettings::register();
redraw_scheduler::initialize_settings(); WindowSettings::register();
renderer::initialize_settings(); redraw_scheduler::RedrawSettings::register();
renderer::cursor_renderer::initialize_settings(); RendererSettings::register();
CursorSettings::register();
let running = Arc::new(AtomicBool::new(true)); let running = Arc::new(AtomicBool::new(true));

@ -10,26 +10,24 @@ lazy_static! {
pub static ref REDRAW_SCHEDULER: RedrawScheduler = RedrawScheduler::new(); pub static ref REDRAW_SCHEDULER: RedrawScheduler = RedrawScheduler::new();
} }
#[derive(Clone)] #[derive(Clone, SettingGroup)]
struct RedrawSettings { pub struct RedrawSettings {
extra_buffer_frames: u64, extra_buffer_frames: u64,
} }
pub fn initialize_settings() { impl Default for RedrawSettings {
let buffer_frames = if SETTINGS fn default() -> Self {
.neovim_arguments Self {
.contains(&String::from("--extraBufferFrames")) extra_buffer_frames: if SETTINGS
{ .neovim_arguments
60 .contains(&"--extraBufferFrames".to_string())
} else { {
1 60
}; } else {
1
SETTINGS.set(&RedrawSettings { },
extra_buffer_frames: buffer_frames, }
}); }
register_nvim_setting!("extra_buffer_frames", RedrawSettings::extra_buffer_frames);
} }
pub struct RedrawScheduler { pub struct RedrawScheduler {

@ -3,6 +3,7 @@ mod cursor_vfx;
use std::collections::HashMap; use std::collections::HashMap;
// use neovide_derive::SettingGroup;
use skulpin::skia_safe::{Canvas, Paint, Path, Point}; use skulpin::skia_safe::{Canvas, Paint, Path, Point};
use super::RenderedWindow; use super::RenderedWindow;
@ -11,7 +12,7 @@ use crate::editor::{Colors, Cursor, CursorShape};
use crate::redraw_scheduler::REDRAW_SCHEDULER; use crate::redraw_scheduler::REDRAW_SCHEDULER;
use crate::renderer::animation_utils::*; use crate::renderer::animation_utils::*;
use crate::renderer::CachingShaper; use crate::renderer::CachingShaper;
use crate::settings::*; use crate::settings::{FromValue, SETTINGS};
use blink::*; use blink::*;
@ -19,9 +20,8 @@ const DEFAULT_CELL_PERCENTAGE: f32 = 1.0 / 8.0;
const STANDARD_CORNERS: &[(f32, f32); 4] = &[(-0.5, -0.5), (0.5, -0.5), (0.5, 0.5), (-0.5, 0.5)]; const STANDARD_CORNERS: &[(f32, f32); 4] = &[(-0.5, -0.5), (0.5, -0.5), (0.5, 0.5), (-0.5, 0.5)];
// ---------------------------------------------------------------------------- #[setting_prefix = "cursor"]
#[derive(Clone, SettingGroup)]
#[derive(Clone)]
pub struct CursorSettings { pub struct CursorSettings {
antialiasing: bool, antialiasing: bool,
animation_length: f32, animation_length: f32,
@ -36,54 +36,24 @@ pub struct CursorSettings {
vfx_particle_curl: f32, vfx_particle_curl: f32,
} }
pub fn initialize_settings() { impl Default for CursorSettings {
SETTINGS.set(&CursorSettings { fn default() -> Self {
antialiasing: true, CursorSettings {
animation_length: 0.13, antialiasing: true,
animate_in_insert_mode: true, animation_length: 0.13,
trail_size: 0.7, animate_in_insert_mode: true,
vfx_mode: cursor_vfx::VfxMode::Disabled, trail_size: 0.7,
vfx_opacity: 200.0, vfx_mode: cursor_vfx::VfxMode::Disabled,
vfx_particle_lifetime: 1.2, vfx_opacity: 200.0,
vfx_particle_density: 7.0, vfx_particle_lifetime: 1.2,
vfx_particle_speed: 10.0, vfx_particle_density: 7.0,
vfx_particle_phase: 1.5, vfx_particle_speed: 10.0,
vfx_particle_curl: 1.0, vfx_particle_phase: 1.5,
}); vfx_particle_curl: 1.0,
}
register_nvim_setting!("cursor_antialiasing", CursorSettings::antialiasing); }
register_nvim_setting!(
"cursor_animate_in_insert_mode",
CursorSettings::animate_in_insert_mode
);
register_nvim_setting!("cursor_animation_length", CursorSettings::animation_length);
register_nvim_setting!("cursor_trail_size", CursorSettings::trail_size);
register_nvim_setting!("cursor_vfx_mode", CursorSettings::vfx_mode);
register_nvim_setting!("cursor_vfx_opacity", CursorSettings::vfx_opacity);
register_nvim_setting!(
"cursor_vfx_particle_lifetime",
CursorSettings::vfx_particle_lifetime
);
register_nvim_setting!(
"cursor_vfx_particle_density",
CursorSettings::vfx_particle_density
);
register_nvim_setting!(
"cursor_vfx_particle_speed",
CursorSettings::vfx_particle_speed
);
register_nvim_setting!(
"cursor_vfx_particle_phase",
CursorSettings::vfx_particle_phase
);
register_nvim_setting!(
"cursor_vfx_particle_curl",
CursorSettings::vfx_particle_curl
);
} }
// ----------------------------------------------------------------------------
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Corner { pub struct Corner {
start_position: Point, start_position: Point,

@ -21,9 +21,8 @@ use crate::editor::{Colors, DrawCommand, Style, WindowDrawCommand};
use crate::settings::*; use crate::settings::*;
use cursor_renderer::CursorRenderer; use cursor_renderer::CursorRenderer;
// ---------------------------------------------------------------------------- #[setting_prefix = "window"]
#[derive(Clone, SettingGroup)]
#[derive(Clone)]
pub struct RendererSettings { pub struct RendererSettings {
position_animation_length: f32, position_animation_length: f32,
scroll_animation_length: f32, scroll_animation_length: f32,
@ -31,31 +30,17 @@ pub struct RendererSettings {
floating_blur: bool, floating_blur: bool,
} }
pub fn initialize_settings() { impl Default for RendererSettings {
SETTINGS.set(&RendererSettings { fn default() -> Self {
position_animation_length: 0.15, Self {
scroll_animation_length: 0.3, position_animation_length: 0.15,
floating_opacity: 0.7, scroll_animation_length: 0.3,
floating_blur: true, floating_opacity: 0.7,
}); floating_blur: true,
}
register_nvim_setting!( }
"window_position_animation_length",
RendererSettings::position_animation_length
);
register_nvim_setting!(
"window_scroll_animation_length",
RendererSettings::scroll_animation_length
);
register_nvim_setting!(
"floating_window_opacity",
RendererSettings::floating_opacity
);
register_nvim_setting!("floating_window_blur", RendererSettings::floating_blur);
} }
// ----------------------------------------------------------------------------
pub struct Renderer { pub struct Renderer {
rendered_windows: HashMap<u64, RenderedWindow>, rendered_windows: HashMap<u64, RenderedWindow>,
cursor_renderer: CursorRenderer, cursor_renderer: CursorRenderer,
@ -90,7 +75,6 @@ impl Renderer {
Renderer { Renderer {
rendered_windows, rendered_windows,
cursor_renderer, cursor_renderer,
current_mode, current_mode,
paint, paint,
shaper, shaper,

@ -20,26 +20,8 @@ lazy_static! {
pub static ref SETTINGS: Settings = Settings::new(); pub static ref SETTINGS: Settings = Settings::new();
} }
// Macro to register settings changed handlers. pub trait SettingGroup {
// Note: Invocations to this macro must happen before the call to Settings::read_initial_values. fn register(&self);
#[macro_export]
macro_rules! register_nvim_setting {
($vim_setting_name: expr, $type_name:ident :: $field_name: ident) => {{
// The update func sets a new value for a setting
fn update_func(value: Value) {
let mut s = SETTINGS.get::<$type_name>();
s.$field_name.from_value(value);
SETTINGS.set(&s);
}
// The reader func retrieves the current value for a setting
fn reader_func() -> Value {
let s = SETTINGS.get::<$type_name>();
s.$field_name.into()
}
SETTINGS.set_setting_handlers($vim_setting_name, update_func, reader_func);
}};
} }
// Function types to handle settings updates // Function types to handle settings updates

@ -6,10 +6,7 @@ mod token;
use crate::settings::SETTINGS; use crate::settings::SETTINGS;
pub use self::{ pub use self::{
layout::KeyboardLayout, layout::KeyboardLayout, modifiers::Modifiers, settings::KeyboardSettings, token::Token,
modifiers::Modifiers,
settings::{initialize_settings, KeyboardSettings},
token::Token,
}; };
type KeycodeToTokenFn<T> = fn(T, bool) -> Option<Token<'static>>; type KeycodeToTokenFn<T> = fn(T, bool) -> Option<Token<'static>>;

@ -1,17 +1,16 @@
use super::KeyboardLayout; use super::KeyboardLayout;
use crate::{ use crate::settings::FromValue;
register_nvim_setting,
settings::{FromValue, Value, SETTINGS},
};
#[derive(Clone)] #[setting_prefix = "keyboard"]
#[derive(Clone, SettingGroup)]
pub struct KeyboardSettings { pub struct KeyboardSettings {
pub layout: KeyboardLayout, pub layout: KeyboardLayout,
} }
pub fn initialize_settings() { impl Default for KeyboardSettings {
SETTINGS.set(&KeyboardSettings { fn default() -> Self {
layout: KeyboardLayout::Qwerty, Self {
}); layout: KeyboardLayout::Qwerty,
register_nvim_setting!("keyboard_layout", KeyboardSettings::layout); }
}
} }

@ -1,7 +1,8 @@
use super::keyboard::initialize_settings as keyboard_initialize_settings;
use crate::settings::*; use crate::settings::*;
#[derive(Clone)] pub use super::keyboard::KeyboardSettings;
#[derive(Clone, SettingGroup)]
pub struct WindowSettings { pub struct WindowSettings {
pub refresh_rate: u64, pub refresh_rate: u64,
pub transparency: f32, pub transparency: f32,
@ -9,22 +10,15 @@ pub struct WindowSettings {
pub fullscreen: bool, pub fullscreen: bool,
} }
pub fn initialize_settings() { impl Default for WindowSettings {
let no_idle = SETTINGS fn default() -> Self {
.neovim_arguments Self {
.contains(&String::from("--noIdle")); refresh_rate: 60,
transparency: 1.0,
SETTINGS.set(&WindowSettings { no_idle: SETTINGS
refresh_rate: 60, .neovim_arguments
transparency: 1.0, .contains(&String::from("--noIdle")),
no_idle, fullscreen: false,
fullscreen: false, }
}); }
register_nvim_setting!("refresh_rate", WindowSettings::refresh_rate);
register_nvim_setting!("transparency", WindowSettings::transparency);
register_nvim_setting!("no_idle", WindowSettings::no_idle);
register_nvim_setting!("fullscreen", WindowSettings::fullscreen);
keyboard_initialize_settings();
} }

Loading…
Cancel
Save