Skip to content

Commit 9c59924

Browse files
committed
config: Handle unknown Action/SystemAction gracefully
1 parent fe529ae commit 9c59924

File tree

3 files changed

+111
-7
lines changed

3 files changed

+111
-7
lines changed

Cargo.lock

Lines changed: 16 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ serde_with = "3.9.0"
1010
thiserror = "1.0.64"
1111
tracing = "0.1.40"
1212
xkbcommon = "0.7.0"
13+
ron = "0.9.0-alpha.0"

config/src/shortcuts/mod.rs

Lines changed: 94 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,17 @@ pub fn system_actions(context: &cosmic_config::Config) -> SystemActions {
5555

5656
// Get the system config first
5757
if let Ok(context) = cosmic_config::Config::system(ID, Config::VERSION) {
58-
match context.get::<SystemActions>("system_actions") {
59-
Ok(system_config) => config = system_config,
58+
match context.get::<SystemActionsImpl>("system_actions") {
59+
Ok(system_config) => config = system_config.0,
6060
Err(why) => {
6161
tracing::error!("failed to read system shortcuts config 'system_actions': {why:?}");
6262
}
6363
}
6464
}
6565

6666
// Then override it with the user's config
67-
match context.get::<SystemActions>("system_actions") {
68-
Ok(user_config) => config.extend(user_config),
67+
match context.get::<SystemActionsImpl>("system_actions") {
68+
Ok(user_config) => config.extend(user_config.0),
6969
Err(why) => {
7070
tracing::error!("failed to read local shortcuts config 'system_actions': {why:?}");
7171
}
@@ -100,10 +100,54 @@ impl Config {
100100
}
101101

102102
/// A map of defined key [Binding]s and their triggerable [Action]s
103-
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
103+
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
104104
#[serde(transparent)]
105105
pub struct Shortcuts(pub HashMap<Binding, Action>);
106106

107+
struct ShortcutMapVisitor;
108+
109+
impl<'de> serde::de::Visitor<'de> for ShortcutMapVisitor {
110+
type Value = Shortcuts;
111+
112+
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
113+
formatter.write_str("Shortcuts Map")
114+
}
115+
116+
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
117+
where
118+
M: serde::de::MapAccess<'de>,
119+
{
120+
let mut map = HashMap::with_capacity(access.size_hint().unwrap_or(0));
121+
122+
while let Some((binding, action)) = access.next_entry::<Binding, &ron::value::RawValue>()? {
123+
match action.into_rust::<Action>() {
124+
Ok(val) => {
125+
map.insert(binding, val);
126+
}
127+
Err(err) => {
128+
tracing::warn!(
129+
"Skipping over invalid Action ({}): {}",
130+
action.get_ron(),
131+
err
132+
);
133+
map.insert(binding, Action::Disable);
134+
}
135+
};
136+
}
137+
138+
Ok(Shortcuts(map))
139+
}
140+
}
141+
142+
impl<'de> Deserialize<'de> for Shortcuts {
143+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
144+
where
145+
D: serde::de::Deserializer<'de>,
146+
{
147+
deserializer.deserialize_map(ShortcutMapVisitor)
148+
}
149+
}
150+
107151
impl Shortcuts {
108152
// pub fn default_shortcuts() -> Self {
109153
// Shortcuts(HashMap::from([
@@ -172,3 +216,48 @@ pub enum State {
172216
Pressed,
173217
Released,
174218
}
219+
220+
pub struct SystemActionsImpl(SystemActions);
221+
222+
struct SystemActionsMapVisitor;
223+
224+
impl<'de> serde::de::Visitor<'de> for SystemActionsMapVisitor {
225+
type Value = SystemActionsImpl;
226+
227+
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
228+
formatter.write_str("SystemActions Map")
229+
}
230+
231+
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
232+
where
233+
M: serde::de::MapAccess<'de>,
234+
{
235+
let mut map = BTreeMap::new();
236+
237+
while let Some((action, command)) = access.next_entry::<&ron::value::RawValue, String>()? {
238+
match action.into_rust::<action::System>() {
239+
Ok(val) => {
240+
map.insert(val, command);
241+
}
242+
Err(err) => {
243+
tracing::warn!(
244+
"Skipping over invalid SystemAction ({}): {}",
245+
action.get_ron(),
246+
err
247+
);
248+
}
249+
};
250+
}
251+
252+
Ok(SystemActionsImpl(map))
253+
}
254+
}
255+
256+
impl<'de> Deserialize<'de> for SystemActionsImpl {
257+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
258+
where
259+
D: serde::de::Deserializer<'de>,
260+
{
261+
deserializer.deserialize_map(SystemActionsMapVisitor)
262+
}
263+
}

0 commit comments

Comments
 (0)