diff --git a/src/config/theme.rs b/src/config/theme.rs index 22fc4a1..fd3927e 100644 --- a/src/config/theme.rs +++ b/src/config/theme.rs @@ -781,6 +781,11 @@ impl ColorTheme { return Theme::dark(); } + // Try user themes loaded at runtime first so users can override built-in themes + if let Some(theme) = load_user_theme(&self.id) { + return theme; + } + // Try embedded themes (generated + custom built-in) for dir in &[&GENERATED_THEMES_DIR, &CUSTOM_THEMES_DIR] { for file in dir.files() { @@ -797,11 +802,6 @@ impl ColorTheme { } } - // Try user themes loaded at runtime - if let Some(theme) = load_user_theme(&self.id) { - return theme; - } - Theme::dark() } } @@ -823,7 +823,20 @@ pub fn load_color_themes() -> Vec { }); seen_ids.insert("default".to_string()); - // 2. Embedded themes (generated + custom built-in) + // 2. User themes from ~/.config/lazygit/themes/ (takes precedence over embedded themes) + if let Some(user_themes) = discover_user_themes() { + for (id, name, appearance) in user_themes { + if seen_ids.insert(id.clone()) { + themes.push(ColorTheme { + name, + id, + appearance, + }); + } + } + } + + // 3. Embedded themes (generated + custom built-in) for dir in &[&GENERATED_THEMES_DIR, &CUSTOM_THEMES_DIR] { for file in dir.files() { if file.path().extension().and_then(|e| e.to_str()) != Some("json") { @@ -843,19 +856,6 @@ pub fn load_color_themes() -> Vec { } } - // 3. User themes from ~/.config/lazygit/themes/ - if let Some(user_themes) = discover_user_themes() { - for (id, name, appearance) in user_themes { - if seen_ids.insert(id.clone()) { - themes.push(ColorTheme { - name, - id, - appearance, - }); - } - } - } - // Dark themes first, then light — alphabetical within each group. // Default stays at index 0. if themes.len() > 1 { @@ -1030,3 +1030,22 @@ fn parse_color(s: &str) -> Option { _ => None, } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_white_theme_loaded_and_light() { + let themes = load_color_themes(); + let white = themes.iter().find(|t| t.id == "white"); + assert!(white.is_some(), "white theme should be available"); + let white = white.unwrap(); + assert_eq!(white.name, "White"); + assert_eq!(white.appearance, ThemeAppearance::Light); + + let theme = white.to_theme(); + assert_eq!(theme.text, Color::Rgb(0, 0, 0)); + assert_eq!(theme.accent, Color::Rgb(0, 0, 0)); + } +} diff --git a/src/themes/white.json b/src/themes/white.json new file mode 100644 index 0000000..adcd822 --- /dev/null +++ b/src/themes/white.json @@ -0,0 +1,50 @@ +{ + "id": "white", + "name": "White", + "appearance": "light", + "primary": "#000000", + "secondary": "#2e2e2e", + "accent": "#000000", + "accent_secondary": "#1a1a1a", + "success": "#2e2e2e", + "error": "#000000", + "warning": "#1a1a1a", + "info": "#3a3a3a", + "text": "#000000", + "text_strong": "#000000", + "text_dimmed": "#6e6e6e", + "background": "#ffffff", + "background_panel": "#ffffff", + "selected_bg": "#e0e0e0", + "separator": "#e8e8e8", + "popup_border": "#000000", + "border": "#000000", + "border_active": "#000000", + "diff_add": "#2e2e2e", + "diff_remove": "#000000", + "diff_context": "#000000", + "diff_add_bg": "#e6ffec", + "diff_remove_bg": "#ffebe9", + "diff_add_word": "#acf2bd", + "diff_remove_word": "#ffc8c8", + "diff_line_number": "#c0c0c0", + "syntax_comment": "#6e6e6e", + "syntax_keyword": "#000000", + "syntax_string": "#3a3a3a", + "syntax_number": "#3a3a3a", + "syntax_function": "#000000", + "syntax_type": "#1a1a1a", + "syntax_operator": "#4a4a4a", + "syntax_punctuation": "#4a4a4a", + "syntax_variable": "#2e2e2e", + "graph_colors": [ + "#000000", + "#2e2e2e", + "#1a1a1a", + "#3a3a3a", + "#4a4a4a", + "#5a5a5a", + "#6e6e6e", + "#808080" + ] +}