theme: Add version control colors (#23529)

Nate Butler created

This PR adds version control-specific theme tokens to the them to allow
styling entries in the git ui and elsewhere.

Release Notes:

- N/A

Change summary

crates/git_ui/src/git_panel.rs      | 10 ++-
crates/git_ui/src/git_ui.rs         | 45 +++++++----------
crates/theme/src/default_colors.rs  | 39 +++++++++++++++
crates/theme/src/fallback_themes.rs | 31 +++++++++++
crates/theme/src/schema.rs          | 80 +++++++++++++++++++++++++++++++
crates/theme/src/styles/colors.rs   | 51 ++++++++++++++++++-
6 files changed, 222 insertions(+), 34 deletions(-)

Detailed changes

crates/git_ui/src/git_panel.rs 🔗

@@ -1083,13 +1083,15 @@ impl GitPanel {
         let mut label_color = cx.theme().colors().text;
         if status_style == StatusStyle::LabelColor {
             label_color = if status.is_conflicted() {
-                cx.theme().status().conflict
+                cx.theme().colors().version_control_conflict
             } else if status.is_modified() {
-                cx.theme().status().modified
+                cx.theme().colors().version_control_modified
             } else if status.is_deleted() {
+                // Don't use `version_control_deleted` here or all the
+                // deleted entries will be likely a red color.
                 cx.theme().colors().text_disabled
             } else {
-                cx.theme().status().created
+                cx.theme().colors().version_control_added
             }
         }
 
@@ -1185,7 +1187,7 @@ impl GitPanel {
                 }),
             )
             .when(status_style == StatusStyle::Icon, |this| {
-                this.child(git_status_icon(status))
+                this.child(git_status_icon(status, cx))
             })
             .child(
                 h_flex()

crates/git_ui/src/git_ui.rs 🔗

@@ -1,8 +1,8 @@
 use ::settings::Settings;
 use git::status::FileStatus;
 use git_panel_settings::GitPanelSettings;
-use gpui::{AppContext, Hsla};
-use ui::{Color, Icon, IconName, IntoElement};
+use gpui::AppContext;
+use ui::{ActiveTheme, Color, Icon, IconName, IntoElement, WindowContext};
 
 pub mod git_panel;
 mod git_panel_settings;
@@ -12,35 +12,28 @@ pub fn init(cx: &mut AppContext) {
     GitPanelSettings::register(cx);
 }
 
-const ADDED_COLOR: Hsla = Hsla {
-    h: 142. / 360.,
-    s: 0.68,
-    l: 0.45,
-    a: 1.0,
-};
-const MODIFIED_COLOR: Hsla = Hsla {
-    h: 48. / 360.,
-    s: 0.76,
-    l: 0.47,
-    a: 1.0,
-};
-const REMOVED_COLOR: Hsla = Hsla {
-    h: 355. / 360.,
-    s: 0.65,
-    l: 0.65,
-    a: 1.0,
-};
-
 // TODO: Add updated status colors to theme
-pub fn git_status_icon(status: FileStatus) -> impl IntoElement {
+pub fn git_status_icon(status: FileStatus, cx: &WindowContext) -> impl IntoElement {
     let (icon_name, color) = if status.is_conflicted() {
-        (IconName::Warning, REMOVED_COLOR)
+        (
+            IconName::Warning,
+            cx.theme().colors().version_control_conflict,
+        )
     } else if status.is_deleted() {
-        (IconName::SquareMinus, REMOVED_COLOR)
+        (
+            IconName::SquareMinus,
+            cx.theme().colors().version_control_deleted,
+        )
     } else if status.is_modified() {
-        (IconName::SquareDot, MODIFIED_COLOR)
+        (
+            IconName::SquareDot,
+            cx.theme().colors().version_control_modified,
+        )
     } else {
-        (IconName::SquarePlus, ADDED_COLOR)
+        (
+            IconName::SquarePlus,
+            cx.theme().colors().version_control_added,
+        )
     };
     Icon::new(icon_name).color(Color::Custom(color))
 }

crates/theme/src/default_colors.rs 🔗

@@ -8,6 +8,25 @@ pub(crate) fn neutral() -> ColorScaleSet {
     sand()
 }
 
+const ADDED_COLOR: Hsla = Hsla {
+    h: 142. / 360.,
+    s: 0.68,
+    l: 0.45,
+    a: 1.0,
+};
+const MODIFIED_COLOR: Hsla = Hsla {
+    h: 48. / 360.,
+    s: 0.76,
+    l: 0.47,
+    a: 1.0,
+};
+const REMOVED_COLOR: Hsla = Hsla {
+    h: 355. / 360.,
+    s: 0.65,
+    l: 0.65,
+    a: 1.0,
+};
+
 /// The default colors for the theme.
 ///
 /// Themes that do not specify all colors are refined off of these defaults.
@@ -116,6 +135,16 @@ impl ThemeColors {
             terminal_ansi_dim_cyan: cyan().light().step_10(),
             terminal_ansi_dim_white: neutral().light().step_11(),
             link_text_hover: orange().light().step_10(),
+            version_control_added: ADDED_COLOR,
+            version_control_added_background: ADDED_COLOR.opacity(0.1),
+            version_control_deleted: REMOVED_COLOR,
+            version_control_deleted_background: REMOVED_COLOR.opacity(0.1),
+            version_control_modified: MODIFIED_COLOR,
+            version_control_modified_background: MODIFIED_COLOR.opacity(0.1),
+            version_control_renamed: MODIFIED_COLOR,
+            version_control_conflict: orange().light().step_12(),
+            version_control_conflict_background: orange().light().step_12().opacity(0.1),
+            version_control_ignored: gray().light().step_12(),
         }
     }
 
@@ -223,6 +252,16 @@ impl ThemeColors {
             terminal_ansi_bright_white: neutral().dark().step_11(),
             terminal_ansi_dim_white: neutral().dark().step_10(),
             link_text_hover: orange().dark().step_10(),
+            version_control_added: ADDED_COLOR,
+            version_control_added_background: ADDED_COLOR.opacity(0.1),
+            version_control_deleted: REMOVED_COLOR,
+            version_control_deleted_background: REMOVED_COLOR.opacity(0.1),
+            version_control_modified: MODIFIED_COLOR,
+            version_control_modified_background: MODIFIED_COLOR.opacity(0.1),
+            version_control_renamed: MODIFIED_COLOR,
+            version_control_conflict: orange().dark().step_12(),
+            version_control_conflict_background: orange().dark().step_12().opacity(0.1),
+            version_control_ignored: gray().dark().step_12(),
         }
     }
 }

crates/theme/src/fallback_themes.rs 🔗

@@ -1,6 +1,6 @@
 use std::sync::Arc;
 
-use gpui::{hsla, FontStyle, FontWeight, HighlightStyle, WindowBackgroundAppearance};
+use gpui::{hsla, FontStyle, FontWeight, HighlightStyle, Hsla, WindowBackgroundAppearance};
 
 use crate::{
     default_color_scales, AccentColors, Appearance, PlayerColors, StatusColors, SyntaxTheme,
@@ -35,6 +35,25 @@ pub(crate) fn zed_default_dark() -> Theme {
     let teal = hsla(187. / 360., 47. / 100., 55. / 100., 1.0);
     let yellow = hsla(39. / 360., 67. / 100., 69. / 100., 1.0);
 
+    const ADDED_COLOR: Hsla = Hsla {
+        h: 142. / 360.,
+        s: 0.68,
+        l: 0.45,
+        a: 1.0,
+    };
+    const MODIFIED_COLOR: Hsla = Hsla {
+        h: 48. / 360.,
+        s: 0.76,
+        l: 0.47,
+        a: 1.0,
+    };
+    const REMOVED_COLOR: Hsla = Hsla {
+        h: 355. / 360.,
+        s: 0.65,
+        l: 0.65,
+        a: 1.0,
+    };
+
     Theme {
         id: "one_dark".to_string(),
         name: "One Dark".into(),
@@ -149,6 +168,16 @@ pub(crate) fn zed_default_dark() -> Theme {
                 scrollbar_track_border: hsla(228. / 360., 8. / 100., 25. / 100., 1.),
                 editor_foreground: hsla(218. / 360., 14. / 100., 71. / 100., 1.),
                 link_text_hover: blue,
+                version_control_added: ADDED_COLOR,
+                version_control_added_background: ADDED_COLOR.opacity(0.1),
+                version_control_deleted: REMOVED_COLOR,
+                version_control_deleted_background: REMOVED_COLOR.opacity(0.1),
+                version_control_modified: MODIFIED_COLOR,
+                version_control_modified_background: MODIFIED_COLOR.opacity(0.1),
+                version_control_renamed: MODIFIED_COLOR,
+                version_control_conflict: crate::orange().light().step_12(),
+                version_control_conflict_background: crate::orange().light().step_12().opacity(0.1),
+                version_control_ignored: crate::gray().light().step_12(),
             },
             status: StatusColors {
                 conflict: yellow,

crates/theme/src/schema.rs 🔗

@@ -552,6 +552,46 @@ pub struct ThemeColorsContent {
 
     #[serde(rename = "link_text.hover")]
     pub link_text_hover: Option<String>,
+
+    /// Added version control color.
+    #[serde(rename = "version_control.added")]
+    pub version_control_added: Option<String>,
+
+    /// Added version control background color.
+    #[serde(rename = "version_control.added_background")]
+    pub version_control_added_background: Option<String>,
+
+    /// Deleted version control color.
+    #[serde(rename = "version_control.deleted")]
+    pub version_control_deleted: Option<String>,
+
+    /// Deleted version control background color.
+    #[serde(rename = "version_control.deleted_background")]
+    pub version_control_deleted_background: Option<String>,
+
+    /// Modified version control color.
+    #[serde(rename = "version_control.modified")]
+    pub version_control_modified: Option<String>,
+
+    /// Modified version control background color.
+    #[serde(rename = "version_control.modified_background")]
+    pub version_control_modified_background: Option<String>,
+
+    /// Renamed version control color.
+    #[serde(rename = "version_control.renamed")]
+    pub version_control_renamed: Option<String>,
+
+    /// Conflict version control color.
+    #[serde(rename = "version_control.conflict")]
+    pub version_control_conflict: Option<String>,
+
+    /// Conflict version control background color.
+    #[serde(rename = "version_control.conflict_background")]
+    pub version_control_conflict_background: Option<String>,
+
+    /// Ignored version control color.
+    #[serde(rename = "version_control.ignored")]
+    pub version_control_ignored: Option<String>,
 }
 
 impl ThemeColorsContent {
@@ -956,6 +996,46 @@ impl ThemeColorsContent {
                 .link_text_hover
                 .as_ref()
                 .and_then(|color| try_parse_color(color).ok()),
+            version_control_added: self
+                .version_control_added
+                .as_ref()
+                .and_then(|color| try_parse_color(color).ok()),
+            version_control_added_background: self
+                .version_control_added_background
+                .as_ref()
+                .and_then(|color| try_parse_color(color).ok()),
+            version_control_deleted: self
+                .version_control_deleted
+                .as_ref()
+                .and_then(|color| try_parse_color(color).ok()),
+            version_control_deleted_background: self
+                .version_control_deleted_background
+                .as_ref()
+                .and_then(|color| try_parse_color(color).ok()),
+            version_control_modified: self
+                .version_control_modified
+                .as_ref()
+                .and_then(|color| try_parse_color(color).ok()),
+            version_control_modified_background: self
+                .version_control_modified_background
+                .as_ref()
+                .and_then(|color| try_parse_color(color).ok()),
+            version_control_renamed: self
+                .version_control_renamed
+                .as_ref()
+                .and_then(|color| try_parse_color(color).ok()),
+            version_control_conflict: self
+                .version_control_conflict
+                .as_ref()
+                .and_then(|color| try_parse_color(color).ok()),
+            version_control_conflict_background: self
+                .version_control_conflict_background
+                .as_ref()
+                .and_then(|color| try_parse_color(color).ok()),
+            version_control_ignored: self
+                .version_control_ignored
+                .as_ref()
+                .and_then(|color| try_parse_color(color).ok()),
         }
     }
 }

crates/theme/src/styles/colors.rs 🔗

@@ -241,10 +241,29 @@ pub struct ThemeColors {
     /// Dim white ANSI terminal color.
     pub terminal_ansi_dim_white: Hsla,
 
-    // ===
-    // UI/Rich Text
-    // ===
+    /// Represents a link text hover color.
     pub link_text_hover: Hsla,
+
+    /// Represents an added entry or hunk in vcs, like git.
+    pub version_control_added: Hsla,
+    /// Represents the line background of an added entry or hunk in vcs, like git.
+    pub version_control_added_background: Hsla,
+    /// Represents a deleted entry in version control systems.
+    pub version_control_deleted: Hsla,
+    /// Represents the background color for deleted entries in version control systems.
+    pub version_control_deleted_background: Hsla,
+    /// Represents a modified entry in version control systems.
+    pub version_control_modified: Hsla,
+    /// Represents the background color for modified entries in version control systems.
+    pub version_control_modified_background: Hsla,
+    /// Represents a renamed entry in version control systems.
+    pub version_control_renamed: Hsla,
+    /// Represents a conflicting entry in version control systems.
+    pub version_control_conflict: Hsla,
+    /// Represents the background color for conflicting entries in version control systems.
+    pub version_control_conflict_background: Hsla,
+    /// Represents an ignored entry in version control systems.
+    pub version_control_ignored: Hsla,
 }
 
 #[derive(EnumIter, Debug, Clone, Copy, AsRefStr)]
@@ -346,6 +365,16 @@ pub enum ThemeColorField {
     TerminalAnsiBrightWhite,
     TerminalAnsiDimWhite,
     LinkTextHover,
+    VersionControlAdded,
+    VersionControlAddedBackground,
+    VersionControlDeleted,
+    VersionControlDeletedBackground,
+    VersionControlModified,
+    VersionControlModifiedBackground,
+    VersionControlRenamed,
+    VersionControlConflict,
+    VersionControlConflictBackground,
+    VersionControlIgnored,
 }
 
 impl ThemeColors {
@@ -455,6 +484,22 @@ impl ThemeColors {
             ThemeColorField::TerminalAnsiBrightWhite => self.terminal_ansi_bright_white,
             ThemeColorField::TerminalAnsiDimWhite => self.terminal_ansi_dim_white,
             ThemeColorField::LinkTextHover => self.link_text_hover,
+            ThemeColorField::VersionControlAdded => self.version_control_added,
+            ThemeColorField::VersionControlAddedBackground => self.version_control_added_background,
+            ThemeColorField::VersionControlDeleted => self.version_control_deleted,
+            ThemeColorField::VersionControlDeletedBackground => {
+                self.version_control_deleted_background
+            }
+            ThemeColorField::VersionControlModified => self.version_control_modified,
+            ThemeColorField::VersionControlModifiedBackground => {
+                self.version_control_modified_background
+            }
+            ThemeColorField::VersionControlRenamed => self.version_control_renamed,
+            ThemeColorField::VersionControlConflict => self.version_control_conflict,
+            ThemeColorField::VersionControlConflictBackground => {
+                self.version_control_conflict_background
+            }
+            ThemeColorField::VersionControlIgnored => self.version_control_ignored,
         }
     }