theme: Pull directory and chevron icons out of `IconTheme::file_icons` (#23155)

Marshall Bowers created

This PR pulls the directory and chevron icons out of the
`IconTheme::file_icons` collection and promotes them to named fields.

This makes things less stringly-typed when looking up these icons.

Release Notes:

- N/A

Change summary

crates/file_icons/src/file_icons.rs | 28 +++++++++----------------
crates/theme/src/icon_theme.rs      | 34 +++++++++++++++++++++++++++---
2 files changed, 40 insertions(+), 22 deletions(-)

Detailed changes

crates/file_icons/src/file_icons.rs 🔗

@@ -16,10 +16,6 @@ pub struct FileIcons {
 
 impl Global for FileIcons {}
 
-const COLLAPSED_DIRECTORY_TYPE: &str = "collapsed_folder";
-const EXPANDED_DIRECTORY_TYPE: &str = "expanded_folder";
-const COLLAPSED_CHEVRON_TYPE: &str = "collapsed_chevron";
-const EXPANDED_CHEVRON_TYPE: &str = "expanded_chevron";
 pub const FILE_TYPES_ASSET: &str = "icons/file_icons/file_types.json";
 
 pub fn init(assets: impl AssetSource, cx: &mut AppContext) {
@@ -73,26 +69,22 @@ impl FileIcons {
     }
 
     pub fn get_folder_icon(expanded: bool, cx: &AppContext) -> Option<SharedString> {
-        let this = cx.try_global::<Self>()?;
+        let icon_theme = &ThemeSettings::get_global(cx).active_icon_theme;
 
-        let key = if expanded {
-            EXPANDED_DIRECTORY_TYPE
+        if expanded {
+            icon_theme.directory_icons.expanded.clone()
         } else {
-            COLLAPSED_DIRECTORY_TYPE
-        };
-
-        this.get_icon_for_type(key, cx)
+            icon_theme.directory_icons.collapsed.clone()
+        }
     }
 
     pub fn get_chevron_icon(expanded: bool, cx: &AppContext) -> Option<SharedString> {
-        let this = cx.try_global::<Self>()?;
+        let icon_theme = &ThemeSettings::get_global(cx).active_icon_theme;
 
-        let key = if expanded {
-            EXPANDED_CHEVRON_TYPE
+        if expanded {
+            icon_theme.chevron_icons.expanded.clone()
         } else {
-            COLLAPSED_CHEVRON_TYPE
-        };
-
-        this.get_icon_for_type(key, cx)
+            icon_theme.chevron_icons.collapsed.clone()
+        }
     }
 }

crates/theme/src/icon_theme.rs 🔗

@@ -24,10 +24,32 @@ pub struct IconTheme {
     pub name: SharedString,
     /// The appearance of the icon theme (e.g., light or dark).
     pub appearance: Appearance,
+    /// The icons used for directories.
+    pub directory_icons: DirectoryIcons,
+    /// The icons used for chevrons.
+    pub chevron_icons: ChevronIcons,
     /// The mapping of file types to icon definitions.
     pub file_icons: HashMap<String, IconDefinition>,
 }
 
+/// The icons used for directories.
+#[derive(Debug, PartialEq)]
+pub struct DirectoryIcons {
+    /// The path to the icon to use for a collapsed directory.
+    pub collapsed: Option<SharedString>,
+    /// The path to the icon to use for an expanded directory.
+    pub expanded: Option<SharedString>,
+}
+
+/// The icons used for chevrons.
+#[derive(Debug, PartialEq)]
+pub struct ChevronIcons {
+    /// The path to the icon to use for a collapsed chevron.
+    pub collapsed: Option<SharedString>,
+    /// The path to the icon to use for an expanded chevron.
+    pub expanded: Option<SharedString>,
+}
+
 /// An icon definition.
 #[derive(Debug, PartialEq)]
 pub struct IconDefinition {
@@ -43,8 +65,6 @@ const FILE_ICONS: &[(&str, &str)] = &[
     ("c", "icons/file_icons/c.svg"),
     ("code", "icons/file_icons/code.svg"),
     ("coffeescript", "icons/file_icons/coffeescript.svg"),
-    ("collapsed_chevron", "icons/file_icons/chevron_right.svg"),
-    ("collapsed_folder", "icons/file_icons/folder.svg"),
     ("cpp", "icons/file_icons/cpp.svg"),
     ("css", "icons/file_icons/css.svg"),
     ("dart", "icons/file_icons/dart.svg"),
@@ -56,8 +76,6 @@ const FILE_ICONS: &[(&str, &str)] = &[
     ("elm", "icons/file_icons/elm.svg"),
     ("erlang", "icons/file_icons/erlang.svg"),
     ("eslint", "icons/file_icons/eslint.svg"),
-    ("expanded_chevron", "icons/file_icons/chevron_down.svg"),
-    ("expanded_folder", "icons/file_icons/folder_open.svg"),
     ("font", "icons/file_icons/font.svg"),
     ("fsharp", "icons/file_icons/fsharp.svg"),
     ("gleam", "icons/file_icons/gleam.svg"),
@@ -115,6 +133,14 @@ pub fn default_icon_theme() -> IconTheme {
         id: DEFAULT_ICON_THEME_ID.into(),
         name: "Zed (Default)".into(),
         appearance: Appearance::Dark,
+        directory_icons: DirectoryIcons {
+            collapsed: Some("icons/file_icons/folder.svg".into()),
+            expanded: Some("icons/file_icons/folder_open.svg".into()),
+        },
+        chevron_icons: ChevronIcons {
+            collapsed: Some("icons/file_icons/chevron_right.svg".into()),
+            expanded: Some("icons/file_icons/chevron_down.svg".into()),
+        },
         file_icons: HashMap::from_iter(FILE_ICONS.into_iter().map(|(ty, path)| {
             (
                 ty.to_string(),