themes: Fix invalid attribute links panic in is_cyclic

Attribute links are not checked for validity in theme validation, and an
invalid link would cause a panic in is_cyclic.

This commit improves the theme validation errors by printing if the
error lies in a theme key or a link.
memfd
Manos Pitsidianakis 2020-04-05 14:47:47 +03:00
parent 4930d1b46c
commit e633434b93
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
1 changed files with 72 additions and 57 deletions

View File

@ -323,7 +323,79 @@ pub struct Theme {
}
impl Theme {
fn validate_keys(
name: &str,
theme: &HashMap<Cow<'static, str>, ThemeAttributeInner>,
hash_set: &HashSet<&'static str>,
) -> Result<()> {
let keys = theme
.keys()
.filter_map(|k| {
if !hash_set.contains(&k.as_ref()) {
Some((None, "key", k.as_ref()))
} else {
None
}
})
.chain(theme.iter().filter_map(|(key, a)| {
if let ThemeValue::Link(ref r) = a.fg {
if !hash_set.contains(&r.as_ref()) {
Some((Some(key), "fg link", r.as_ref()))
} else {
None
}
} else {
None
}
}))
.chain(theme.iter().filter_map(|(key, a)| {
if let ThemeValue::Link(ref r) = a.bg {
if !hash_set.contains(&r.as_ref()) {
Some((Some(key), "bg link", r.as_ref()))
} else {
None
}
} else {
None
}
}))
.chain(theme.iter().filter_map(|(key, a)| {
if let ThemeValue::Link(ref r) = a.attrs {
if !hash_set.contains(&r.as_ref()) {
Some((Some(key), "attrs link", r.as_ref()))
} else {
None
}
} else {
None
}
}))
.collect::<SmallVec<[(Option<_>, &'_ str, &'_ str); 128]>>();
if !keys.is_empty() {
return Err(format!(
"{} theme contains unrecognized theme keywords: {}",
name,
keys.into_iter()
.map(|(key_opt, desc, link)| if let Some(key) = key_opt {
format!("{} {}: \"{}\"", key, desc, link)
} else {
format!("{}: \"{}\"", desc, link)
})
.collect::<SmallVec<[String; 128]>>()
.join(", ")
)
.into());
}
Ok(())
}
pub fn validate(&self) -> Result<()> {
let hash_set: HashSet<&'static str> = DEFAULT_KEYS.into_iter().map(|k| *k).collect();
Theme::validate_keys("light", &self.light, &hash_set)?;
Theme::validate_keys("dark", &self.dark, &hash_set)?;
for (name, t) in self.other_themes.iter() {
Theme::validate_keys(name, t, &hash_set)?;
}
if let Err(err) = is_cyclic(&self.light) {
return Err(MeliError::new(format!(
"light theme contains a cycle: {}",
@ -344,63 +416,6 @@ impl Theme {
)));
}
}
let hash_set: HashSet<&'static str> = DEFAULT_KEYS.into_iter().map(|k| *k).collect();
let keys = self
.light
.keys()
.filter_map(|k| {
if !hash_set.contains(&k.as_ref()) {
Some(k.as_ref())
} else {
None
}
})
.collect::<SmallVec<[&'_ str; 128]>>();
if !keys.is_empty() {
return Err(format!(
"light theme contains unrecognized theme keywords: {}",
keys.join(", ")
)
.into());
}
let keys = self
.dark
.keys()
.filter_map(|k| {
if !hash_set.contains(&k.as_ref()) {
Some(k.as_ref())
} else {
None
}
})
.collect::<SmallVec<[&'_ str; 128]>>();
if !keys.is_empty() {
return Err(format!(
"light theme contains unrecognized theme keywords: {}",
keys.join(", ")
)
.into());
}
for (name, t) in self.other_themes.iter() {
let keys = t
.keys()
.filter_map(|k| {
if !hash_set.contains(&k.as_ref()) {
Some(k.as_ref())
} else {
None
}
})
.collect::<SmallVec<[&'_ str; 128]>>();
if !keys.is_empty() {
return Err(format!(
"`{}` theme contains unrecognized theme keywords: {}",
name,
keys.join(", ")
)
.into());
}
}
Ok(())
}