This commit is contained in:
Jacob 2025-08-27 03:14:36 +09:00 committed by GitHub
commit 8ff12fe770
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 102 additions and 15 deletions

View file

@ -162,8 +162,15 @@ impl MentionUri {
FileIcons::get_icon(abs_path, cx).unwrap_or_else(|| IconName::File.path().into()) FileIcons::get_icon(abs_path, cx).unwrap_or_else(|| IconName::File.path().into())
} }
MentionUri::PastedImage => IconName::Image.path().into(), MentionUri::PastedImage => IconName::Image.path().into(),
MentionUri::Directory { .. } => FileIcons::get_folder_icon(false, cx) MentionUri::Directory { abs_path } => {
.unwrap_or_else(|| IconName::Folder.path().into()), let name = abs_path
.file_name()
.and_then(|name| name.to_str())
.unwrap_or_default();
FileIcons::get_folder_icon(false, name, cx)
.unwrap_or_else(|| IconName::Folder.path().into())
}
MentionUri::Symbol { .. } => IconName::Code.path().into(), MentionUri::Symbol { .. } => IconName::Code.path().into(),
MentionUri::Thread { .. } => IconName::Thread.path().into(), MentionUri::Thread { .. } => IconName::Thread.path().into(),
MentionUri::TextThread { .. } => IconName::Thread.path().into(), MentionUri::TextThread { .. } => IconName::Thread.path().into(),

View file

@ -594,7 +594,8 @@ impl ContextPickerCompletionProvider {
}; };
let crease_icon_path = if is_directory { let crease_icon_path = if is_directory {
FileIcons::get_folder_icon(false, cx).unwrap_or_else(|| IconName::Folder.path().into()) FileIcons::get_folder_icon(false, &file_name, cx)
.unwrap_or_else(|| IconName::Folder.path().into())
} else { } else {
FileIcons::get_icon(Path::new(&full_path), cx) FileIcons::get_icon(Path::new(&full_path), cx)
.unwrap_or_else(|| IconName::File.path().into()) .unwrap_or_else(|| IconName::File.path().into())

View file

@ -330,7 +330,7 @@ pub fn render_file_context_entry(
}); });
let file_icon = if is_directory { let file_icon = if is_directory {
FileIcons::get_folder_icon(false, cx) FileIcons::get_folder_icon(false, &file_name, cx)
} else { } else {
FileIcons::get_icon(path, cx) FileIcons::get_icon(path, cx)
} }

View file

@ -633,10 +633,16 @@ impl PickerDelegate for OpenPathDelegate {
if !settings.file_icons { if !settings.file_icons {
return None; return None;
} }
let path = path::Path::new(&candidate.path.string);
let icon = if candidate.is_dir { let icon = if candidate.is_dir {
FileIcons::get_folder_icon(false, cx)? let name = path
.file_name()
.and_then(|name| name.to_str())
.unwrap_or_default();
FileIcons::get_folder_icon(false, name, cx)?
} else { } else {
let path = path::Path::new(&candidate.path.string);
FileIcons::get_icon(path, cx)? FileIcons::get_icon(path, cx)?
}; };
Some(Icon::from_path(icon).color(Color::Muted)) Some(Icon::from_path(icon).color(Color::Muted))

View file

@ -93,18 +93,49 @@ impl FileIcons {
}) })
} }
pub fn get_folder_icon(expanded: bool, cx: &App) -> Option<SharedString> { pub fn get_folder_icon(expanded: bool, name: &str, cx: &App) -> Option<SharedString> {
fn get_folder_icon(icon_theme: &Arc<IconTheme>, expanded: bool) -> Option<SharedString> { fn get_folder_icon(
icon_theme: &Arc<IconTheme>,
name: &str,
expanded: bool,
) -> Option<SharedString> {
if expanded { if expanded {
let named_icon = icon_theme
.named_directory_icons
.expanded
.get(name)
.and_then(|key| icon_theme.file_icons.get(key))
.map(|icon_definition| icon_definition.path.clone());
if let Some(named_icon) = named_icon {
return Some(named_icon);
}
icon_theme.directory_icons.expanded.clone() icon_theme.directory_icons.expanded.clone()
} else { } else {
let named_icon = icon_theme
.named_directory_icons
.collapsed
.get(name)
.and_then(|key| icon_theme.file_icons.get(key))
.map(|icon_definition| icon_definition.path.clone());
if let Some(named_icon) = named_icon {
return Some(named_icon);
}
icon_theme.directory_icons.collapsed.clone() icon_theme.directory_icons.collapsed.clone()
} }
} }
get_folder_icon(&ThemeSettings::get_global(cx).active_icon_theme, expanded).or_else(|| { get_folder_icon(
&ThemeSettings::get_global(cx).active_icon_theme,
name,
expanded,
)
.or_else(|| {
Self::default_icon_theme(cx) Self::default_icon_theme(cx)
.and_then(|icon_theme| get_folder_icon(&icon_theme, expanded)) .and_then(|icon_theme| get_folder_icon(&icon_theme, name, expanded))
}) })
} }

View file

@ -2319,7 +2319,7 @@ impl OutlinePanel {
is_active, is_active,
); );
let icon = if settings.folder_icons { let icon = if settings.folder_icons {
FileIcons::get_folder_icon(is_expanded, cx) FileIcons::get_folder_icon(is_expanded, &name, cx)
} else { } else {
FileIcons::get_chevron_icon(is_expanded, cx) FileIcons::get_chevron_icon(is_expanded, cx)
} }
@ -2416,7 +2416,7 @@ impl OutlinePanel {
.unwrap_or_default(); .unwrap_or_default();
let color = entry_git_aware_label_color(git_status, is_ignored, is_active); let color = entry_git_aware_label_color(git_status, is_ignored, is_active);
let icon = if settings.folder_icons { let icon = if settings.folder_icons {
FileIcons::get_folder_icon(is_expanded, cx) FileIcons::get_folder_icon(is_expanded, &name, cx)
} else { } else {
FileIcons::get_chevron_icon(is_expanded, cx) FileIcons::get_chevron_icon(is_expanded, cx)
} }

View file

@ -4641,7 +4641,12 @@ impl ProjectPanel {
} }
_ => { _ => {
if show_folder_icons { if show_folder_icons {
FileIcons::get_folder_icon(is_expanded, cx) let name = entry
.path
.file_name()
.and_then(|name| name.to_str())
.unwrap_or_default();
FileIcons::get_folder_icon(is_expanded, name, cx)
} else { } else {
FileIcons::get_chevron_icon(is_expanded, cx) FileIcons::get_chevron_icon(is_expanded, cx)
} }

View file

@ -28,6 +28,8 @@ pub struct IconTheme {
pub appearance: Appearance, pub appearance: Appearance,
/// The icons used for directories. /// The icons used for directories.
pub directory_icons: DirectoryIcons, pub directory_icons: DirectoryIcons,
/// The icons used for named directories.
pub named_directory_icons: NamedDirectoryIcons,
/// The icons used for chevrons. /// The icons used for chevrons.
pub chevron_icons: ChevronIcons, pub chevron_icons: ChevronIcons,
/// The mapping of file stems to their associated icon keys. /// The mapping of file stems to their associated icon keys.
@ -47,6 +49,15 @@ pub struct DirectoryIcons {
pub expanded: Option<SharedString>, pub expanded: Option<SharedString>,
} }
/// The icons used for directories with specific names
#[derive(Debug, PartialEq)]
pub struct NamedDirectoryIcons {
/// The paths for icons to use for collapsed directories.
pub collapsed: HashMap<String, String>,
/// The paths for icons to use for expanded directories.
pub expanded: HashMap<String, String>,
}
/// The icons used for chevrons. /// The icons used for chevrons.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct ChevronIcons { pub struct ChevronIcons {
@ -392,6 +403,10 @@ static DEFAULT_ICON_THEME: LazyLock<Arc<IconTheme>> = LazyLock::new(|| {
collapsed: Some("icons/file_icons/folder.svg".into()), collapsed: Some("icons/file_icons/folder.svg".into()),
expanded: Some("icons/file_icons/folder_open.svg".into()), expanded: Some("icons/file_icons/folder_open.svg".into()),
}, },
named_directory_icons: NamedDirectoryIcons {
collapsed: Default::default(),
expanded: Default::default(),
},
chevron_icons: ChevronIcons { chevron_icons: ChevronIcons {
collapsed: Some("icons/file_icons/chevron_right.svg".into()), collapsed: Some("icons/file_icons/chevron_right.svg".into()),
expanded: Some("icons/file_icons/chevron_down.svg".into()), expanded: Some("icons/file_icons/chevron_down.svg".into()),

View file

@ -21,6 +21,8 @@ pub struct IconThemeContent {
#[serde(default)] #[serde(default)]
pub directory_icons: DirectoryIconsContent, pub directory_icons: DirectoryIconsContent,
#[serde(default)] #[serde(default)]
pub named_directory_icons: NamedDirectoryIconsContent,
#[serde(default)]
pub chevron_icons: ChevronIconsContent, pub chevron_icons: ChevronIconsContent,
#[serde(default)] #[serde(default)]
pub file_stems: HashMap<String, String>, pub file_stems: HashMap<String, String>,
@ -36,6 +38,14 @@ pub struct DirectoryIconsContent {
pub expanded: Option<SharedString>, pub expanded: Option<SharedString>,
} }
#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
pub struct NamedDirectoryIconsContent {
#[serde(default)]
pub collapsed: HashMap<String, String>,
#[serde(default)]
pub expanded: HashMap<String, String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)] #[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
pub struct ChevronIconsContent { pub struct ChevronIconsContent {
pub collapsed: Option<SharedString>, pub collapsed: Option<SharedString>,

View file

@ -13,8 +13,8 @@ use util::ResultExt;
use crate::{ use crate::{
Appearance, AppearanceContent, ChevronIcons, DEFAULT_ICON_THEME_NAME, DirectoryIcons, Appearance, AppearanceContent, ChevronIcons, DEFAULT_ICON_THEME_NAME, DirectoryIcons,
IconDefinition, IconTheme, Theme, ThemeFamily, ThemeFamilyContent, default_icon_theme, IconDefinition, IconTheme, NamedDirectoryIcons, Theme, ThemeFamily, ThemeFamilyContent,
read_icon_theme, read_user_theme, refine_theme_family, default_icon_theme, read_icon_theme, read_user_theme, refine_theme_family,
}; };
/// The metadata for a theme. /// The metadata for a theme.
@ -298,6 +298,14 @@ impl ThemeRegistry {
let mut file_suffixes = default_icon_theme.file_suffixes.clone(); let mut file_suffixes = default_icon_theme.file_suffixes.clone();
file_suffixes.extend(icon_theme.file_suffixes); file_suffixes.extend(icon_theme.file_suffixes);
let mut named_directory_icons_expanded =
default_icon_theme.named_directory_icons.expanded.clone();
named_directory_icons_expanded.extend(icon_theme.named_directory_icons.expanded);
let mut named_directory_icons_collapsed =
default_icon_theme.named_directory_icons.collapsed.clone();
named_directory_icons_collapsed.extend(icon_theme.named_directory_icons.collapsed);
let icon_theme = IconTheme { let icon_theme = IconTheme {
id: uuid::Uuid::new_v4().to_string(), id: uuid::Uuid::new_v4().to_string(),
name: icon_theme.name.into(), name: icon_theme.name.into(),
@ -309,6 +317,10 @@ impl ThemeRegistry {
collapsed: icon_theme.directory_icons.collapsed.map(resolve_icon_path), collapsed: icon_theme.directory_icons.collapsed.map(resolve_icon_path),
expanded: icon_theme.directory_icons.expanded.map(resolve_icon_path), expanded: icon_theme.directory_icons.expanded.map(resolve_icon_path),
}, },
named_directory_icons: NamedDirectoryIcons {
collapsed: named_directory_icons_collapsed,
expanded: named_directory_icons_expanded,
},
chevron_icons: ChevronIcons { chevron_icons: ChevronIcons {
collapsed: icon_theme.chevron_icons.collapsed.map(resolve_icon_path), collapsed: icon_theme.chevron_icons.collapsed.map(resolve_icon_path),
expanded: icon_theme.chevron_icons.expanded.map(resolve_icon_path), expanded: icon_theme.chevron_icons.expanded.map(resolve_icon_path),