From 8c855680e7813d10b31f2e8ed92d64cbdfea4b4f Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 17 Jul 2023 13:09:47 -0700 Subject: [PATCH] Make file types live reload --- assets/icons/file_icons/file_types.json | 3 + crates/project_panel/src/file_associations.rs | 58 ++++++++++--------- crates/project_panel/src/project_panel.rs | 15 +++-- crates/zed/src/main.rs | 25 ++++++++ 4 files changed, 68 insertions(+), 33 deletions(-) diff --git a/assets/icons/file_icons/file_types.json b/assets/icons/file_icons/file_types.json index 8803647857..401e6d1686 100644 --- a/assets/icons/file_icons/file_types.json +++ b/assets/icons/file_icons/file_types.json @@ -67,6 +67,9 @@ "log": "log" }, "types": { + "default": { + "icon": "icons/file_icons/quill/file.svg" + }, "directory": { "icon": "icons/file_icons/quill/folder.svg" }, diff --git a/crates/project_panel/src/file_associations.rs b/crates/project_panel/src/file_associations.rs index e1fb9b3c64..2d3413ef34 100644 --- a/crates/project_panel/src/file_associations.rs +++ b/crates/project_panel/src/file_associations.rs @@ -4,6 +4,7 @@ use collections::HashMap; use gpui::{AppContext, AssetSource}; use serde_derive::Deserialize; +use util::iife; #[derive(Deserialize, Debug)] struct TypeConfig { @@ -16,9 +17,9 @@ pub struct FileAssociations { types: HashMap, } -pub const TEXT_FILE_ASSET: &'static str = "icons/file_icons/quill/file.svg"; const DIRECTORY_TYPE: &'static str = "directory"; const EXPANDED_DIRECTORY_TYPE: &'static str = "expanded_directory"; +pub const FILE_TYPES_ASSET: &'static str = "icons/file_icons/file_types.json"; pub fn init(assets: impl AssetSource, cx: &mut AppContext) { cx.set_global(FileAssociations::new(assets)) @@ -28,8 +29,9 @@ impl FileAssociations { pub fn new(assets: impl AssetSource) -> Self { assets .load("icons/file_icons/file_types.json") - .map(|file| { - serde_json::from_str::(str::from_utf8(&file).unwrap()).unwrap() + .and_then(|file| { + serde_json::from_str::(str::from_utf8(&file).unwrap()) + .map_err(Into::into) }) .unwrap_or_else(|_| FileAssociations { suffixes: HashMap::default(), @@ -37,35 +39,37 @@ impl FileAssociations { }) } - pub fn get_icon(path: &Path, cx: &AppContext) -> Option> { - if !cx.has_global::() { - return None; - } + pub fn get_icon(path: &Path, cx: &AppContext) -> Arc { + iife!({ + let this = cx.has_global::().then(|| cx.global::())?; - let this = cx.global::(); - let suffix = path.extension()?.to_str()?; + iife!({ + let suffix = path.extension()?.to_str()?; - this.suffixes - .get(suffix) - .and_then(|type_str| this.types.get(type_str)) - .map(|type_config| type_config.icon.clone()) + this.suffixes + .get(suffix) + .and_then(|type_str| this.types.get(type_str)) + .map(|type_config| type_config.icon.clone()) + }) + .or_else(|| this.types.get("default").map(|config| config.icon.clone())) + }) + .unwrap_or_else(|| Arc::from("".to_string())) } - pub fn get_folder_icon(expanded: bool, cx: &AppContext) -> Option> { - if !cx.has_global::() { - return None; - } + pub fn get_folder_icon(expanded: bool, cx: &AppContext) -> Arc { + iife!({ + let this = cx.has_global::().then(|| cx.global::())?; - let this = cx.global::(); + let key = if expanded { + EXPANDED_DIRECTORY_TYPE + } else { + DIRECTORY_TYPE + }; - let key = if expanded { - EXPANDED_DIRECTORY_TYPE - } else { - DIRECTORY_TYPE - }; - - this.types - .get(key) - .map(|type_config| type_config.icon.clone()) + this.types + .get(key) + .map(|type_config| type_config.icon.clone()) + }) + .unwrap_or_else(|| Arc::from("".to_string())) } } diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index dd40fdd561..f8e1b223d3 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1,11 +1,12 @@ -mod file_associations; +pub mod file_associations; mod project_panel_settings; use context_menu::{ContextMenu, ContextMenuItem}; use db::kvp::KEY_VALUE_STORE; use drag_and_drop::{DragAndDrop, Draggable}; use editor::{Cancel, Editor}; -use file_associations::{FileAssociations, TEXT_FILE_ASSET}; +use file_associations::FileAssociations; + use futures::stream::StreamExt; use gpui::{ actions, @@ -234,6 +235,10 @@ impl ProjectPanel { }) .detach(); + cx.observe_global::(|_, cx| { + cx.notify(); + }).detach(); + let view_id = cx.view_id(); let mut this = Self { project: project.clone(), @@ -1189,11 +1194,9 @@ impl ProjectPanel { let is_expanded = expanded_entry_ids.binary_search(&entry.id).is_ok(); let icon = show_file_icons .then(|| match entry.kind { - EntryKind::File(_) => FileAssociations::get_icon(&entry.path, cx) - .or_else(|| Some(TEXT_FILE_ASSET.into())), + EntryKind::File(_) => FileAssociations::get_icon(&entry.path, cx), _ => FileAssociations::get_folder_icon(is_expanded, cx), - }) - .flatten(); + }); let mut details = EntryDetails { filename: entry diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index e85113d57d..87e00a70c2 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -166,6 +166,7 @@ fn main() { cx.spawn(|cx| watch_themes(fs.clone(), cx)).detach(); cx.spawn(|_| watch_languages(fs.clone(), languages.clone())) .detach(); + watch_file_types(fs.clone(), cx); languages.set_theme(theme::current(cx).clone()); cx.observe_global::({ @@ -685,6 +686,25 @@ async fn watch_languages(fs: Arc, languages: Arc) -> O Some(()) } +#[cfg(debug_assertions)] +fn watch_file_types(fs: Arc, cx: &mut AppContext) { + cx.spawn(|mut cx| async move { + let mut events = fs + .watch( + "assets/icons/file_icons/file_types.json".as_ref(), + Duration::from_millis(100), + ) + .await; + while (events.next().await).is_some() { + cx.update(|cx| { + cx.update_global(|file_types, _| { + *file_types = project_panel::file_associations::FileAssociations::new(Assets); + }); + }) + } + }).detach() +} + #[cfg(not(debug_assertions))] async fn watch_themes(_fs: Arc, _cx: AsyncAppContext) -> Option<()> { None @@ -695,6 +715,11 @@ async fn watch_languages(_: Arc, _: Arc) -> Option<()> None } +#[cfg(not(debug_assertions))] +fn watch_file_types(fs: Arc, cx: &mut AppContext) { + None +} + fn connect_to_cli( server_name: &str, ) -> Result<(mpsc::Receiver, IpcSender)> {