Skip to content

Commit

Permalink
Fix remember window size (#2120)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kethku committed Nov 11, 2023
1 parent 7ca01d6 commit b79b7cc
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 78 deletions.
38 changes: 23 additions & 15 deletions lua/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
---@field register_clipboard boolean
---@field register_right_click boolean
---@field enable_focus_command boolean
---@field global_variable_settings string[]
---@field option_settings string[]

---@type Args
local args = ...
Expand Down Expand Up @@ -62,23 +64,29 @@ vim.api.nvim_create_user_command("NeovideFocus", function()
rpcnotify("neovide.focus_window")
end, {})

vim.api.nvim_create_autocmd({ "OptionSet" }, {
pattern = "columns",
once = false,
nested = true,
callback = function()
rpcnotify("neovide.columns", tonumber(vim.v.option_new))
end
})
vim.api.nvim_exec([[
function! WatchGlobal(variable, callback)
call dictwatcheradd(g:, a:variable, a:callback)
endfunction
]], false)

vim.api.nvim_create_autocmd({ "OptionSet" }, {
pattern = "lines",
once = false,
nested = true,
callback = function()
rpcnotify("neovide.lines", tonumber(vim.v.option_new))
for _,global_variable_setting in ipairs(args.global_variable_settings) do
local callback = function()
rpcnotify("setting_changed", global_variable_setting, vim.g["neovide_" .. global_variable_setting])
end
})
vim.fn.WatchGlobal("neovide_" .. global_variable_setting, callback)
end

for _,option_setting in ipairs(args.option_settings) do
vim.api.nvim_create_autocmd({ "OptionSet" }, {
pattern = option_setting,
once = false,
nested = true,
callback = function()
rpcnotify("option_changed", option_setting, vim.o[option_setting])
end
})
end

-- Create auto command for retrieving exit code from neovim on quit.
vim.api.nvim_create_autocmd({ "VimLeavePre" }, {
Expand Down
41 changes: 32 additions & 9 deletions neovide-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,33 +40,56 @@ fn struct_stream(name: Ident, prefix: String, data: &DataStruct) -> TokenStream
Some(ref ident) => {
let vim_setting_name = format!("{prefix}{ident}");

let location = match option(field) {
Ok(option) => match option {
Some(option_name) => quote! {{ crate::settings::SettingLocation::NeovimOption(#option_name.to_owned()) }},
None => quote! {{ crate::settings::SettingLocation::NeovideGlobal(#vim_setting_name.to_owned()) }},
},
let option_name = match option(field) {
Ok(option_name) => option_name,
Err(error) => {
return error.to_compile_error();
}
};

let location = match &option_name {
Some(option_name) => quote! {{ crate::settings::SettingLocation::NeovimOption(#option_name.to_owned()) }},
None => quote! {{ crate::settings::SettingLocation::NeovideGlobal(#vim_setting_name.to_owned()) }},
};

let field_ident = field.ident.as_ref().unwrap();
let case_name = field_ident.to_string().to_case(Case::Pascal);
let case_ident = Ident::new(&case_name, field_ident.span());

// Only create a reader function for global neovide variables
let reader = if option_name.is_none() {
quote! {
fn reader(settings: &crate::settings::Settings) -> Option<rmpv::Value> {
let s = settings.get::<#name>();
Some(s.#ident.into())
}
}
} else {
quote! {
fn reader(_settings: &crate::settings::Settings) -> Option<rmpv::Value> {
None
}
}
};

quote! {{
fn update(settings: &crate::settings::Settings, value: rmpv::Value) {
fn update(settings: &crate::settings::Settings, value: rmpv::Value, send_changed_event: bool) {
let mut s = settings.get::<#name>();
s.#ident.parse_from_value(value);
settings.set(&s);
crate::event_aggregator::EVENT_AGGREGATOR.send(
#event_name::#case_ident(s.#ident.clone()),
);
if send_changed_event {
crate::event_aggregator::EVENT_AGGREGATOR.send(
#event_name::#case_ident(s.#ident.clone()),
);
}
}

#reader

settings.set_setting_handlers(
#location,
update,
reader,
);
}}
}
Expand Down
1 change: 0 additions & 1 deletion src/bridge/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ async fn launch(grid_size: Option<Dimensions>) -> Result<NeovimSession> {

start_ui_command_handler(Arc::clone(&session.neovim));
SETTINGS.read_initial_values(&session.neovim).await?;
SETTINGS.setup_changed_listeners(&session.neovim).await?;

let mut options = UiAttachOptions::new();
options.set_linegrid_external(true);
Expand Down
26 changes: 25 additions & 1 deletion src/bridge/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use nvim_rs::Neovim;
use rmpv::Value;

use super::setup_intro_message_autocommand;
use crate::bridge::NeovimWriter;
use crate::{
bridge::NeovimWriter,
settings::{SettingLocation, SETTINGS},
};

const INIT_LUA: &str = include_str!("../../lua/init.lua");

Expand Down Expand Up @@ -60,6 +63,22 @@ pub async fn setup_neovide_specific_state(
let register_clipboard = should_handle_clipboard;
let register_right_click = cfg!(target_os = "windows");

let settings = SETTINGS.setting_locations();
let global_variable_settings = settings
.iter()
.filter_map(|s| match s {
SettingLocation::NeovideGlobal(setting) => Some(Value::from(setting.to_owned())),
_ => None,
})
.collect::<Vec<_>>();
let option_settings = settings
.iter()
.filter_map(|s| match s {
SettingLocation::NeovimOption(setting) => Some(Value::from(setting.to_owned())),
_ => None,
})
.collect::<Vec<_>>();

let args = Value::from(vec![
(Value::from("neovide_channel_id"), neovide_channel),
(
Expand All @@ -70,6 +89,11 @@ pub async fn setup_neovide_specific_state(
Value::from("register_right_click"),
Value::from(register_right_click),
),
(
Value::from("global_variable_settings"),
Value::from(global_variable_settings),
),
(Value::from("option_settings"), Value::from(option_settings)),
]);

nvim.execute_lua(INIT_LUA, vec![args])
Expand Down
87 changes: 35 additions & 52 deletions src/settings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ pub trait SettingGroup {
}

// Function types to handle settings updates
type UpdateHandlerFunc = fn(&Settings, Value);
type UpdateHandlerFunc = fn(&Settings, Value, bool);
type ReaderHandlerFunc = fn(&Settings) -> Option<Value>;

// The Settings struct acts as a global container where each of Neovide's subsystems can store
// their own settings. It will also coordinate updates between Neovide and nvim to make sure the
Expand All @@ -44,7 +45,8 @@ type UpdateHandlerFunc = fn(&Settings, Value);
// nvim will get out of sync.
pub struct Settings {
settings: RwLock<HashMap<TypeId, Box<dyn Any + Send + Sync>>>,
listeners: RwLock<HashMap<SettingLocation, UpdateHandlerFunc>>,
updaters: RwLock<HashMap<SettingLocation, UpdateHandlerFunc>>,
readers: RwLock<HashMap<SettingLocation, ReaderHandlerFunc>>,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
Expand All @@ -59,18 +61,24 @@ impl Settings {
fn new() -> Self {
Self {
settings: RwLock::new(HashMap::new()),
listeners: RwLock::new(HashMap::new()),
updaters: RwLock::new(HashMap::new()),
readers: RwLock::new(HashMap::new()),
}
}

pub fn set_setting_handlers(
&self,
setting_location: SettingLocation,
update_func: UpdateHandlerFunc,
reader_func: ReaderHandlerFunc,
) {
self.listeners
self.updaters
.write()
.insert(setting_location.clone(), update_func);

self.readers
.write()
.insert(setting_location.clone(), reader_func);
}

pub fn set<T: Clone + Send + Sync + 'static>(&self, t: &T) {
Expand All @@ -91,25 +99,35 @@ impl Settings {
(*value).clone()
}

pub fn setting_locations(&self) -> Vec<SettingLocation> {
self.updaters.read().keys().cloned().collect()
}

pub async fn read_initial_values(&self, nvim: &Neovim<NeovimWriter>) -> Result<()> {
let keys: Vec<SettingLocation> = self.listeners.read().keys().cloned().collect();
let keys: Vec<SettingLocation> = self.updaters.read().keys().cloned().collect();

for location in keys {
match &location {
SettingLocation::NeovideGlobal(name) => {
let variable_name = format!("neovide_{name}");
match nvim.get_var(&variable_name).await {
Ok(value) => {
self.listeners.read().get(&location).unwrap()(self, value);
self.updaters.read().get(&location).unwrap()(self, value, false);
}
Err(error) => {
trace!("Initial value load failed for {}: {}", name, error);
let value = self.readers.read().get(&location).unwrap()(self);
if let Some(value) = value {
nvim.set_var(&variable_name, value).await.with_context(|| {
format!("Could not set initial value for {name}")
})?;
}
}
}
}
SettingLocation::NeovimOption(name) => match nvim.get_option(name).await {
Ok(value) => {
self.listeners.read().get(&location).unwrap()(self, value);
self.updaters.read().get(&location).unwrap()(self, value, false);
}
Err(error) => {
trace!("Initial value load failed for {}: {}", name, error);
Expand All @@ -120,55 +138,17 @@ impl Settings {
Ok(())
}

pub async fn setup_changed_listeners(&self, nvim: &Neovim<NeovimWriter>) -> Result<()> {
let keys: Vec<SettingLocation> = self.listeners.read().keys().cloned().collect();

for location in keys {
match &location {
SettingLocation::NeovideGlobal(name) => {
let vimscript = format!(
concat!(
"exe \"",
"fun! NeovideNotify{0}Changed(d, k, z)\n",
"call rpcnotify(g:neovide_channel_id, 'setting_changed', '{0}', g:neovide_{0})\n",
"endf\n",
"call dictwatcheradd(g:, 'neovide_{0}', 'NeovideNotify{0}Changed')\"",
),
name
);
nvim.command(&vimscript)
.await
.with_context(|| format!("Could not setup setting notifier for {name}"))?;
}
SettingLocation::NeovimOption(name) => {
let vimscript = format!(
concat!(
"exe \"",
"autocmd OptionSet {0} call rpcnotify(g:neovide_channel_id, 'option_changed', '{0}', &{0})\n",
"\"",
),
name
);
nvim.command(&vimscript)
.await
.with_context(|| format!("Could not setup setting notifier for {name}"))?;
}
}
}
Ok(())
}

pub fn handle_setting_changed_notification(&self, arguments: Vec<Value>) {
let mut arguments = arguments.into_iter();
let (name, value) = (arguments.next().unwrap(), arguments.next().unwrap());

let name: Result<String, _> = name.try_into();
let name = name.unwrap();

self.listeners
self.updaters
.read()
.get(&SettingLocation::NeovideGlobal(name))
.unwrap()(self, value);
.unwrap()(self, value, true);
}

pub fn handle_option_changed_notification(&self, arguments: Vec<Value>) {
Expand All @@ -178,10 +158,10 @@ impl Settings {
let name: Result<String, _> = name.try_into();
let name = name.unwrap();

self.listeners
self.updaters
.read()
.get(&SettingLocation::NeovimOption(name))
.unwrap()(self, value);
.unwrap()(self, value, true);
}

pub fn register<T: SettingGroup>(&self) {
Expand Down Expand Up @@ -226,10 +206,13 @@ mod tests {

let location = SettingLocation::NeovideGlobal("foo".to_owned());

fn noop_update(_settings: &Settings, _v: Value) {}
fn noop_update(_settings: &Settings, _value: Value, _send_changed_event: bool) {}
fn noop_read(_settings: &Settings) -> Option<Value> {
None
}

settings.set_setting_handlers(location.clone(), noop_update);
let listeners = settings.listeners.read();
settings.set_setting_handlers(location.clone(), noop_update, noop_read);
let listeners = settings.updaters.read();
let listener = listeners.get(&location).unwrap();
assert_eq!(&(noop_update as UpdateHandlerFunc), listener);
}
Expand Down

0 comments on commit b79b7cc

Please sign in to comment.