Skip to content

Commit

Permalink
Fix alacritty msg config toml replacement
Browse files Browse the repository at this point in the history
This fixes a regression introduced in bd49067 which broke the override
of configuration file variables using `alacritty msg config`.

To fix this the `replace` functionality was rewritten to behave more
like the `serde_utils::merge` where entire values are inserted into the
existing structure rather than separating the keys from the values.

Fixes: bd49067 (Switch to TOML configuration format)
  • Loading branch information
chrisduerr committed Jun 15, 2023
1 parent be03eff commit afffdbe
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 64 deletions.
27 changes: 7 additions & 20 deletions alacritty/src/window_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ pub struct WindowContext {
master_fd: RawFd,
#[cfg(not(windows))]
shell_pid: u32,
ipc_config: Vec<(String, toml::Value)>,
ipc_config: Vec<toml::Value>,
config: Rc<UiConfig>,
}

Expand Down Expand Up @@ -273,13 +273,12 @@ impl WindowContext {
// Apply each option, removing broken ones.
let mut i = 0;
while i < self.ipc_config.len() {
let (key, value) = &self.ipc_config[i];

match config.replace(key, value.clone()) {
let option = &self.ipc_config[i];
match config.replace(option.clone()) {
Err(err) => {
error!(
target: LOG_TARGET_IPC_CONFIG,
"Unable to override option '{}': {}", key, err
"Unable to override option '{}': {}", option, err
);
self.ipc_config.swap_remove(i);
},
Expand Down Expand Up @@ -367,21 +366,9 @@ impl WindowContext {
self.ipc_config.clear();
} else {
for option in &ipc_config.options {
// Separate config key/value.
let (key, value) = match option.split_once('=') {
Some(split) => split,
None => {
error!(
target: LOG_TARGET_IPC_CONFIG,
"'{}': IPC config option missing value", option
);
continue;
},
};

// Try and parse value as toml.
match toml::from_str(value) {
Ok(value) => self.ipc_config.push((key.to_owned(), value)),
// Try and parse option as toml.
match toml::from_str(option) {
Ok(value) => self.ipc_config.push(value),
Err(err) => error!(
target: LOG_TARGET_IPC_CONFIG,
"'{}': Invalid IPC config value: {:?}", option, err
Expand Down
24 changes: 10 additions & 14 deletions alacritty_config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ use serde::Deserialize;
use toml::Value;

pub trait SerdeReplace {
fn replace(&mut self, key: &str, value: Value) -> Result<(), Box<dyn Error>>;
fn replace(&mut self, value: Value) -> Result<(), Box<dyn Error>>;
}

macro_rules! impl_replace {
($($ty:ty),*$(,)*) => {
$(
impl SerdeReplace for $ty {
fn replace(&mut self, key: &str, value: Value) -> Result<(), Box<dyn Error>> {
replace_simple(self, key, value)
fn replace(&mut self, value: Value) -> Result<(), Box<dyn Error>> {
replace_simple(self, value)
}
}
)*
Expand All @@ -35,33 +35,29 @@ impl_replace!(
#[cfg(target_os = "macos")]
impl_replace!(winit::platform::macos::OptionAsAlt,);

fn replace_simple<'de, D>(data: &mut D, key: &str, value: Value) -> Result<(), Box<dyn Error>>
fn replace_simple<'de, D>(data: &mut D, value: Value) -> Result<(), Box<dyn Error>>
where
D: Deserialize<'de>,
{
if !key.is_empty() {
let error = format!("Fields \"{key}\" do not exist");
return Err(error.into());
}
*data = D::deserialize(value)?;

Ok(())
}

impl<'de, T: Deserialize<'de>> SerdeReplace for Vec<T> {
fn replace(&mut self, key: &str, value: Value) -> Result<(), Box<dyn Error>> {
replace_simple(self, key, value)
fn replace(&mut self, value: Value) -> Result<(), Box<dyn Error>> {
replace_simple(self, value)
}
}

impl<'de, T: Deserialize<'de>> SerdeReplace for Option<T> {
fn replace(&mut self, key: &str, value: Value) -> Result<(), Box<dyn Error>> {
replace_simple(self, key, value)
fn replace(&mut self, value: Value) -> Result<(), Box<dyn Error>> {
replace_simple(self, value)
}
}

impl<'de, T: Deserialize<'de>> SerdeReplace for HashMap<String, T> {
fn replace(&mut self, key: &str, value: Value) -> Result<(), Box<dyn Error>> {
replace_simple(self, key, value)
fn replace(&mut self, value: Value) -> Result<(), Box<dyn Error>> {
replace_simple(self, value)
}
}
38 changes: 19 additions & 19 deletions alacritty_config_derive/src/serde_replace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,7 @@ pub fn derive(input: TokenStream) -> TokenStream {
pub fn derive_direct(ident: Ident, generics: Generics) -> TokenStream2 {
quote! {
impl <#generics> alacritty_config::SerdeReplace for #ident <#generics> {
fn replace(&mut self, key: &str, value: toml::Value) -> Result<(), Box<dyn std::error::Error>> {
if !key.is_empty() {
let error = format!("Fields \"{}\" do not exist", key);
return Err(error.into());
}
fn replace(&mut self, value: toml::Value) -> Result<(), Box<dyn std::error::Error>> {
*self = serde::Deserialize::deserialize(value)?;

Ok(())
Expand All @@ -53,19 +49,23 @@ pub fn derive_recursive<T>(
quote! {
#[allow(clippy::extra_unused_lifetimes)]
impl <'de, #constrained> alacritty_config::SerdeReplace for #ident <#unconstrained> {
fn replace(&mut self, key: &str, value: toml::Value) -> Result<(), Box<dyn std::error::Error>> {
if key.is_empty() {
*self = serde::Deserialize::deserialize(value)?;
return Ok(());
}

let (field, next_key) = key.split_once('.').unwrap_or((key, ""));
match field {
#replace_arms
_ => {
let error = format!("Field \"{}\" does not exist", field);
return Err(error.into());
fn replace(&mut self, value: toml::Value) -> Result<(), Box<dyn std::error::Error>> {
match value.as_table() {
Some(table) => {
for (field, next_value) in table {
let next_value = next_value.clone();
let value = value.clone();

match field.as_str() {
#replace_arms
_ => {
let error = format!("Field \"{}\" does not exist", field);
return Err(error.into());
},
}
}
},
None => *self = serde::Deserialize::deserialize(value)?,
}

Ok(())
Expand Down Expand Up @@ -95,11 +95,11 @@ fn match_arms<T>(fields: &Punctuated<Field, T>) -> TokenStream2 {
return Error::new(ident.span(), MULTIPLE_FLATTEN_ERROR).to_compile_error();
} else if flatten {
flattened_arm = Some(quote! {
_ => alacritty_config::SerdeReplace::replace(&mut self.#ident, key, value)?,
_ => alacritty_config::SerdeReplace::replace(&mut self.#ident, value)?,
});
} else {
stream.extend(quote! {
#literal => alacritty_config::SerdeReplace::replace(&mut self.#ident, next_key, value)?,
#literal => alacritty_config::SerdeReplace::replace(&mut self.#ident, next_value)?,
});
}
}
Expand Down
12 changes: 6 additions & 6 deletions alacritty_config_derive/tests/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ impl Log for Logger {
fn field_replacement() {
let mut test = Test::default();

let value = toml::Value::Integer(13);
test.replace("nesting.field2", value).unwrap();
let value = toml::from_str("nesting.field2=13").unwrap();
test.replace(value).unwrap();

assert_eq!(test.nesting.field2, Some(13));
}
Expand All @@ -183,8 +183,8 @@ fn field_replacement() {
fn replace_derive() {
let mut test = Test::default();

let value = toml::Value::Integer(9);
test.replace("nesting.newtype", value).unwrap();
let value = toml::from_str("nesting.newtype=9").unwrap();
test.replace(value).unwrap();

assert_eq!(test.nesting.newtype, NewType(9));
}
Expand All @@ -193,8 +193,8 @@ fn replace_derive() {
fn replace_flatten() {
let mut test = Test::default();

let value = toml::Value::Integer(7);
test.replace("flatty", value).unwrap();
let value = toml::from_str("flatty=7").unwrap();
test.replace(value).unwrap();

assert_eq!(test.flatten.flatty, 7);
}
7 changes: 2 additions & 5 deletions alacritty_terminal/src/ansi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,9 @@ impl<'de> serde::Deserialize<'de> for CursorShapeShim {
}

impl alacritty_config::SerdeReplace for CursorShapeShim {
fn replace(&mut self, key: &str, value: toml::Value) -> Result<(), Box<dyn std::error::Error>> {
if !key.is_empty() {
return Err(format!("Fields \"{0}\" do not exist", key).into());
}

fn replace(&mut self, value: toml::Value) -> Result<(), Box<dyn std::error::Error>> {
*self = serde::Deserialize::deserialize(value)?;

Ok(())
}
}

0 comments on commit afffdbe

Please sign in to comment.