ui/themes: load other themes from ./themes/ dir

memfd
Manos Pitsidianakis 2020-01-24 16:05:25 +02:00
parent ab0b4f5168
commit 5230ce2d03
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
3 changed files with 120 additions and 28 deletions

View File

@ -289,14 +289,14 @@ pub struct Settings {
impl FileSettings {
pub fn new() -> Result<FileSettings> {
let xdg_dirs = xdg::BaseDirectories::with_prefix("meli");
let config_path = match env::var("MELI_CONFIG") {
Ok(path) => PathBuf::from(path),
Err(_) => {
let xdg_dirs = xdg::BaseDirectories::with_prefix("meli").unwrap();
xdg_dirs
.place_config_file("config")
.expect("cannot create configuration directory")
}
Err(_) => xdg_dirs
.as_ref()
.unwrap()
.place_config_file("config")
.expect("cannot create configuration directory"),
};
if !config_path.exists() {
println!(
@ -341,12 +341,54 @@ impl FileSettings {
let Theme {
light: default_light,
dark: default_dark,
..
} = Theme::default();
for (k, v) in default_light.into_iter() {
if !s.terminal.themes.light.contains_key(&k) {
s.terminal.themes.light.insert(k, v);
}
}
for theme in s.terminal.themes.other_themes.values_mut() {
for (k, v) in default_dark.clone().into_iter() {
if !theme.contains_key(&k) {
theme.insert(k, v);
}
}
}
if let Ok(xdg_dirs) = xdg_dirs {
for theme_folder in xdg_dirs.find_config_files("themes") {
let read_dir = std::fs::read_dir(theme_folder)?;
for theme in read_dir {
let theme = theme?;
if theme.path().is_file() {
use std::os::unix::ffi::OsStrExt;
let theme_name = if let Some(n) = theme
.path()
.file_stem()
.map(|f| String::from_utf8_lossy(f.as_bytes()).into_owned())
{
n
} else {
continue;
};
let mut t: HashMap<std::borrow::Cow<'static, str>, ThemeAttributeInner> =
toml::from_str(&pp::pp(theme.path())?).map_err(|err| {
format!(
"Could not parse theme in `{}`: {}",
theme.path().display(),
err.to_string()
)
})?;
for (k, v) in default_dark.clone().into_iter() {
if !t.contains_key(&k) {
t.insert(k, v);
}
}
s.terminal.themes.other_themes.insert(theme_name, t);
}
}
}
}
for (k, v) in default_dark.into_iter() {
if !s.terminal.themes.dark.contains_key(&k) {
s.terminal.themes.dark.insert(k, v);
@ -359,7 +401,7 @@ impl FileSettings {
pub fn validate(path: &str) -> Result<()> {
let s = pp::pp(path)?;
let s: FileSettings = toml::from_str(&s).map_err(|e| {
let mut s: FileSettings = toml::from_str(&s).map_err(|e| {
MeliError::new(format!(
"{}:\nConfig file contains errors: {}",
path,
@ -377,6 +419,44 @@ impl FileSettings {
);
}
}
if let Ok(xdg_dirs) = xdg::BaseDirectories::with_prefix("meli") {
for theme_folder in xdg_dirs.find_config_files("themes") {
let read_dir = std::fs::read_dir(theme_folder)?;
for theme in read_dir {
let theme = theme?;
if theme.path().is_file() {
use std::os::unix::ffi::OsStrExt;
let theme_name = if let Some(n) = theme
.path()
.file_stem()
.map(|f| String::from_utf8_lossy(f.as_bytes()).into_owned())
{
n
} else {
continue;
};
let t: HashMap<std::borrow::Cow<'static, str>, ThemeAttributeInner> =
toml::from_str(&pp::pp(theme.path())?).map_err(|err| {
format!(
"Could not parse theme in `{}`: {}",
theme.path().display(),
err.to_string()
)
})?;
s.terminal.themes.other_themes.insert(theme_name, t);
}
}
}
}
match s.terminal.theme.as_str() {
"dark" | "light" => {}
t if s.terminal.themes.other_themes.contains_key(t) => {}
t => {
return Err(MeliError::new(format!("Theme `{}` was not found.", t)));
}
}
for (name, acc) in s.accounts {
let FileAccount {
root_folder,
@ -745,12 +825,11 @@ mod pp {
}
}
pub fn pp(path: &str) -> Result<String> {
let p = &Path::new(path);
let p_buf: PathBuf = if p.is_relative() {
p.canonicalize()?
pub fn pp<P: AsRef<Path>>(path: P) -> Result<String> {
let p_buf: PathBuf = if path.as_ref().is_relative() {
path.as_ref().canonicalize()?
} else {
p.to_path_buf()
path.as_ref().to_path_buf()
};
let ret = pp_helper(&p_buf, 0);

View File

@ -251,7 +251,7 @@ impl<T: Serialize> Serialize for ThemeValue<T> {
{
match self {
ThemeValue::Value(s) => s.serialize(serializer),
_ => unreachable!(),
ThemeValue::Link(s) => serializer.serialize_str(s.as_ref()),
}
}
}
@ -560,14 +560,15 @@ impl Serialize for Theme {
{
let mut dark: HashMap<Cow<'static, str>, ThemeAttribute> = Default::default();
let mut light: HashMap<Cow<'static, str>, ThemeAttribute> = Default::default();
let mut other_themes: HashMap<String, _> = Default::default();
for k in self.dark.keys() {
dark.insert(
k.clone(),
ThemeAttribute {
fg: unlink_fg(&self.light, k),
bg: unlink_bg(&self.light, k),
attrs: unlink_attrs(&self.light, k),
fg: unlink_fg(&self.dark, k),
bg: unlink_bg(&self.dark, k),
attrs: unlink_attrs(&self.dark, k),
},
);
}
@ -583,16 +584,25 @@ impl Serialize for Theme {
);
}
#[derive(Serialize)]
struct ThemeSer {
light: HashMap<Cow<'static, str>, ThemeAttribute>,
dark: HashMap<Cow<'static, str>, ThemeAttribute>,
for (name, t) in self.other_themes.iter() {
let mut new_map: HashMap<Cow<'static, str>, ThemeAttribute> = Default::default();
for k in t.keys() {
new_map.insert(
k.clone(),
ThemeAttribute {
fg: unlink_fg(&t, k),
bg: unlink_bg(&t, k),
attrs: unlink_attrs(&t, k),
},
);
}
other_themes.insert(name.to_string(), new_map);
}
use serde::ser::SerializeStruct;
let mut s = serializer.serialize_struct("ThemeSer", 2)?;
s.serialize_field("light", &light)?;
s.serialize_field("dark", &dark)?;
s.end()
other_themes.insert("light".to_string(), light);
other_themes.insert("dark".to_string(), dark);
other_themes.serialize(serializer)
}
}

View File

@ -1098,8 +1098,8 @@ impl Serialize for Color {
Color::Green | Color::Byte(2) => serializer.serialize_str("Green"),
Color::Byte(3) => serializer.serialize_str("Olive"),
Color::Byte(4) => serializer.serialize_str("Navy"),
Color::Byte(5) => serializer.serialize_str("Purple"),
Color::Byte(6) => serializer.serialize_str("Teal"),
Color::Byte(5) | Color::Magenta => serializer.serialize_str("Purple"),
Color::Byte(6) | Color::Cyan => serializer.serialize_str("Teal"),
Color::Byte(7) => serializer.serialize_str("Silver"),
Color::Byte(8) => serializer.serialize_str("Grey"),
Color::Red | Color::Byte(9) => serializer.serialize_str("Red"),
@ -1349,7 +1349,10 @@ impl Serialize for Color {
Color::Byte(253) => serializer.serialize_str("Grey85"),
Color::Byte(254) => serializer.serialize_str("Grey89"),
Color::Byte(255) => serializer.serialize_str("Grey93"),
_ => serializer.serialize_str("Black"), // FIXME
Color::Rgb(r, g, b) => {
serializer.serialize_str(&format!("#{:02x}{:02x}{:02x}", r, g, b))
}
Color::Default => serializer.serialize_str("Default"),
}
}
}