summaryrefslogtreecommitdiffstats
path: root/src/ui
diff options
context:
space:
mode:
authorChristoph Rüßler <christoph.ruessler@mailbox.org>2023-06-25 14:09:40 +0200
committerGitHub <noreply@github.com>2023-06-25 14:09:40 +0200
commit3c9c266c01cddb583d38d5eeac853b6091ced0c4 (patch)
treea1672382d733d28cac5ef5c6d47cc21def52e5cf /src/ui
parent999912c3474f019dc6d3bf1f31b09c30b6d4fb1a (diff)
Simplify theme overrides (#1652)
* Simplify theme overrides Theme overrides are now loaded the same way key overrides are loaded. The config file, `theme.ron`, does not have to contain a complete theme anymore. Instead, it is possible to specify only the values that are supposed to override their corresponding default values. * Document breaking change in changelog * Test that override differs from default * Convert existing theme to patch
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/style.rs109
1 files changed, 67 insertions, 42 deletions
diff --git a/src/ui/style.rs b/src/ui/style.rs
index fe6c3cd8..1139cfe7 100644
--- a/src/ui/style.rs
+++ b/src/ui/style.rs
@@ -1,21 +1,15 @@
use anyhow::Result;
use asyncgit::{DiffLineType, StatusItemType};
use ratatui::style::{Color, Modifier, Style};
-use ron::{
- de::from_bytes,
- ser::{to_string_pretty, PrettyConfig},
-};
+use ron::ser::{to_string_pretty, PrettyConfig};
use serde::{Deserialize, Serialize};
-use std::{
- fs::{self, File},
- io::{Read, Write},
- path::PathBuf,
- rc::Rc,
-};
+use std::{fs::File, io::Write, path::PathBuf, rc::Rc};
+use struct_patch::Patch;
pub type SharedTheme = Rc<Theme>;
-#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
+#[derive(Serialize, Deserialize, Debug, Copy, Clone, Patch)]
+#[patch_derive(Serialize, Deserialize)]
pub struct Theme {
selected_tab: Color,
command_fg: Color,
@@ -261,44 +255,46 @@ impl Theme {
.bg(self.push_gauge_bg)
}
- // This will only be called when theme.ron doesn't already exists
- fn save(&self, theme_file: &PathBuf) -> Result<()> {
- let mut file = File::create(theme_file)?;
- let data = to_string_pretty(self, PrettyConfig::default())?;
+ fn load_patch(theme_path: &PathBuf) -> Result<ThemePatch> {
+ let file = File::open(theme_path)?;
+
+ Ok(ron::de::from_reader(file)?)
+ }
+
+ fn load_old_theme(theme_path: &PathBuf) -> Result<Self> {
+ let old_file = File::open(theme_path)?;
+
+ Ok(ron::de::from_reader::<File, Self>(old_file)?)
+ }
+
+ // This is supposed to be called when theme.ron doesn't already exists.
+ fn save_patch(&self, theme_path: &PathBuf) -> Result<()> {
+ let mut file = File::create(theme_path)?;
+ let patch = self.into_patch_by_diff(Self::default());
+ let data = to_string_pretty(&patch, PrettyConfig::default())?;
+
file.write_all(data.as_bytes())?;
+
Ok(())
}
- fn read_file(theme_file: PathBuf) -> Result<Self> {
- let mut f = File::open(theme_file)?;
- let mut buffer = Vec::new();
- f.read_to_end(&mut buffer)?;
- Ok(from_bytes(&buffer)?)
- }
+ pub fn init(theme_path: &PathBuf) -> Self {
+ let mut theme = Self::default();
+
+ if let Ok(patch) = Self::load_patch(theme_path) {
+ theme.apply(patch);
+ } else if let Ok(old_theme) = Self::load_old_theme(theme_path)
+ {
+ theme = old_theme;
- pub fn init(file: &PathBuf) -> Result<Self> {
- if file.exists() {
- match Self::read_file(file.clone()) {
- Err(e) => {
- let config_path = file.clone();
- let config_path_old =
- format!("{}.old", file.to_string_lossy());
- fs::rename(
- config_path.clone(),
- config_path_old.clone(),
- )?;
-
- Self::default().save(file)?;
-
- Err(anyhow::anyhow!("{}\n Old file was renamed to {:?}.\n Defaults loaded and saved as {:?}",
- e,config_path_old,config_path.to_string_lossy()))
- }
- Ok(res) => Ok(res),
+ if theme.save_patch(theme_path).is_ok() {
+ log::info!("Converted old theme to new format.");
+ } else {
+ log::warn!("Failed to save theme in new format.");
}
- } else {
- Self::default().save(file)?;
- Ok(Self::default())
}
+
+ theme
}
}
@@ -329,3 +325,32 @@ impl Default for Theme {
}
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use pretty_assertions::assert_eq;
+ use std::io::Write;
+ use tempfile::NamedTempFile;
+
+ #[test]
+ fn test_smoke() {
+ let mut file = NamedTempFile::new().unwrap();
+
+ writeln!(
+ file,
+ r"
+(
+ selection_bg: Some(White),
+)
+"
+ )
+ .unwrap();
+
+ let theme = Theme::init(&file.path().to_path_buf());
+
+ assert_eq!(theme.selection_fg, Theme::default().selection_fg);
+ assert_eq!(theme.selection_bg, Color::White);
+ assert_ne!(theme.selection_bg, Theme::default().selection_bg);
+ }
+}