From d26f76ba90d5ca314fea8d63d1f0ccf1b1f92905 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 13 Jul 2023 16:56:39 -0700 Subject: [PATCH] Add suffix based file icons --- crates/language/src/language.rs | 19 ++++++++++ crates/project/src/project.rs | 5 +++ crates/project_panel/src/project_panel.rs | 45 +++++++++++++++++------ crates/theme/src/theme.rs | 3 +- crates/zed/src/languages/toml/config.toml | 1 + styles/src/style_tree/project_panel.ts | 3 +- 6 files changed, 62 insertions(+), 14 deletions(-) diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 50a0b4b161..f416422fa2 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -342,6 +342,8 @@ pub struct LanguageConfig { pub block_comment: Option<(Arc, Arc)>, #[serde(default)] pub overrides: HashMap, + #[serde(default)] + pub icon_path: Option>, } #[derive(Debug, Default)] @@ -408,6 +410,7 @@ impl Default for LanguageConfig { line_comment: Default::default(), block_comment: Default::default(), overrides: Default::default(), + icon_path: Default::default(), } } } @@ -752,6 +755,22 @@ impl LanguageRegistry { self.get_or_load_language(|config| UniCase::new(config.name.as_ref()) == name) } + pub fn icon_for_suffix( + self: &Arc, + suffix: &str, + ) -> Option> { + let state = self.state.read(); + state.available_languages + .iter() + .find(|langauge| { + langauge.config.path_suffixes.iter().any(|s| s == suffix) + }) + .map(|language| { + language.config.icon_path.clone() + }) + .flatten() + } + pub fn language_for_name_or_extension( self: &Arc, string: &str, diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 5bb8af3f38..1158f2fa56 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -2474,6 +2474,11 @@ impl Project { }) } + pub fn icon_for_path(&self, path: &Path) -> Option> { + self.languages + .icon_for_suffix(path.extension()?.to_str()?) + } + fn detect_language_for_buffer( &mut self, buffer_handle: &ModelHandle, diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 5442a8be74..ce86b1e768 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -44,6 +44,7 @@ use workspace::{ const PROJECT_PANEL_KEY: &'static str = "ProjectPanel"; const NEW_ENTRY_ID: ProjectEntryId = ProjectEntryId::MAX; +const TEXT_FILE_ASSET: &'static str = "icons/radix/file-text.svg"; pub struct ProjectPanel { project: ModelHandle, @@ -94,6 +95,7 @@ pub enum ClipboardEntry { #[derive(Debug, PartialEq, Eq)] pub struct EntryDetails { filename: String, + icon: Option>, path: Arc, depth: usize, kind: EntryKind, @@ -1180,6 +1182,15 @@ impl ProjectPanel { for entry in visible_worktree_entries[entry_range].iter() { let status = git_status_setting.then(|| entry.git_status).flatten(); + let icon = match entry.kind { + EntryKind::File(_) => self + .project + .read(cx) + .icon_for_path(&entry.path) + .or_else(|| Some(TEXT_FILE_ASSET.into())), + _ => None, + }; + let mut details = EntryDetails { filename: entry .path @@ -1187,6 +1198,7 @@ impl ProjectPanel { .unwrap_or(root_name) .to_string_lossy() .to_string(), + icon, path: entry.path.clone(), depth: entry.path.components().count(), kind: entry.kind, @@ -1254,23 +1266,32 @@ impl ProjectPanel { .unwrap_or(style.text.color); Flex::row() - .with_child( - if kind.is_dir() { - if details.is_expanded { - Svg::new("icons/chevron_down_8.svg").with_color(style.icon_color) - } else { - Svg::new("icons/chevron_right_8.svg").with_color(style.icon_color) - } - .constrained() + .with_child(if kind.is_dir() { + if details.is_expanded { + Svg::new("icons/chevron_down_8.svg").with_color(style.icon_color) + } else { + Svg::new("icons/chevron_right_8.svg").with_color(style.icon_color) + } + .constrained() + .with_max_width(style.directory_icon_size) + .with_max_height(style.directory_icon_size) + .aligned() + .constrained() + .with_width(style.directory_icon_size) + } else { + if let Some(icon) = &details.icon { + Svg::new(icon.to_string()) + .with_color(style.icon_color) + .constrained() } else { Empty::new().constrained() } - .with_max_width(style.icon_size) - .with_max_height(style.icon_size) + .with_max_width(style.file_icon_size) + .with_max_height(style.file_icon_size) .aligned() .constrained() - .with_width(style.icon_size), - ) + .with_width(style.file_icon_size) + }) .with_child(if show_editor && editor.is_some() { ChildView::new(editor.as_ref().unwrap(), cx) .contained() diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index b7a7408bef..53a0629198 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -481,7 +481,8 @@ pub struct ProjectPanelEntry { pub container: ContainerStyle, pub text: TextStyle, pub icon_color: Color, - pub icon_size: f32, + pub directory_icon_size: f32, + pub file_icon_size: f32, pub icon_spacing: f32, pub status: EntryStatus, } diff --git a/crates/zed/src/languages/toml/config.toml b/crates/zed/src/languages/toml/config.toml index 4e89f5cabd..5a3fc9d8b8 100644 --- a/crates/zed/src/languages/toml/config.toml +++ b/crates/zed/src/languages/toml/config.toml @@ -1,5 +1,6 @@ name = "TOML" path_suffixes = ["toml"] +icon_path = "icons/radix/gear.svg" line_comment = "# " autoclose_before = ",]}" brackets = [ diff --git a/styles/src/style_tree/project_panel.ts b/styles/src/style_tree/project_panel.ts index af997d0a6e..c2719e935e 100644 --- a/styles/src/style_tree/project_panel.ts +++ b/styles/src/style_tree/project_panel.ts @@ -47,7 +47,8 @@ export default function project_panel(): any { height: 22, background: background(theme.middle), icon_color: foreground(theme.middle, "variant"), - icon_size: 7, + directory_icon_size: 7, + file_icon_size: 14, icon_spacing: 5, text: text(theme.middle, "sans", "variant", { size: "sm" }), status: {