Refactor file icons to use IconTheme (#23153)

This PR adds the initial concept of an `IconTheme` and refactors
`FileIcons` to use it to resolve the icons.

The `IconTheme` will ultimately be used to allow users to select a
different set of icons to use. Currently, however, this is just laying
the foundation for that work.

The association between file types and icons is now handled by the icon
theme when we resolve file icons. This mapping has been moved out of
`file_types.json` and into `icon_theme.rs`.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2025-01-14 17:49:36 -05:00 committed by GitHub
parent 07d582401a
commit 88e42cc7aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 196 additions and 226 deletions

View file

@ -13,9 +13,11 @@ path = "src/file_icons.rs"
doctest = false
[dependencies]
collections.workspace = true
gpui.workspace = true
util.workspace = true
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
collections.workspace = true
settings.workspace = true
theme.workspace = true
util.workspace = true

View file

@ -4,18 +4,14 @@ use collections::HashMap;
use gpui::{AppContext, AssetSource, Global, SharedString};
use serde_derive::Deserialize;
use settings::Settings;
use theme::ThemeSettings;
use util::{maybe, paths::PathExt};
#[derive(Deserialize, Debug)]
struct TypeConfig {
icon: SharedString,
}
#[derive(Deserialize, Debug)]
pub struct FileIcons {
stems: HashMap<String, String>,
suffixes: HashMap<String, String>,
types: HashMap<String, TypeConfig>,
}
impl Global for FileIcons {}
@ -37,14 +33,13 @@ impl FileIcons {
pub fn new(assets: impl AssetSource) -> Self {
assets
.load("icons/file_icons/file_types.json")
.load(FILE_TYPES_ASSET)
.ok()
.flatten()
.and_then(|file| serde_json::from_str::<FileIcons>(str::from_utf8(&file).unwrap()).ok())
.unwrap_or_else(|| FileIcons {
stems: HashMap::default(),
suffixes: HashMap::default(),
types: HashMap::default(),
})
}
@ -57,20 +52,24 @@ impl FileIcons {
let suffix = path.icon_stem_or_suffix()?;
if let Some(type_str) = this.stems.get(suffix) {
return this.get_type_icon(type_str);
return this.get_icon_for_type(type_str, cx);
}
this.suffixes
.get(suffix)
.and_then(|type_str| this.get_type_icon(type_str))
.and_then(|type_str| this.get_icon_for_type(type_str, cx))
})
.or_else(|| this.get_type_icon("default"))
.or_else(|| this.get_icon_for_type("default", cx))
}
pub fn get_type_icon(&self, typ: &str) -> Option<SharedString> {
self.types
pub fn get_icon_for_type(&self, typ: &str, cx: &AppContext) -> Option<SharedString> {
let theme_settings = ThemeSettings::get_global(cx);
theme_settings
.active_icon_theme
.file_icons
.get(typ)
.map(|type_config| type_config.icon.clone())
.map(|icon_definition| icon_definition.path.clone())
}
pub fn get_folder_icon(expanded: bool, cx: &AppContext) -> Option<SharedString> {
@ -82,7 +81,7 @@ impl FileIcons {
COLLAPSED_DIRECTORY_TYPE
};
this.get_type_icon(key)
this.get_icon_for_type(key, cx)
}
pub fn get_chevron_icon(expanded: bool, cx: &AppContext) -> Option<SharedString> {
@ -94,6 +93,6 @@ impl FileIcons {
COLLAPSED_CHEVRON_TYPE
};
this.get_type_icon(key)
this.get_icon_for_type(key, cx)
}
}