From 7dac5594cdb02259c455cee90f57fb610b8c6162 Mon Sep 17 00:00:00 2001 From: Daste Date: Fri, 20 Sep 2024 20:44:13 +0200 Subject: [PATCH] file_finder: Display file icons (#18091) This PR adds file icons (like in tabs, the project panel and tab switcher) to the file finder popup. It's similar to [tab_switcher icons](https://github.com/zed-industries/zed/pull/17115), but simpler, because we're only dealing with actual files. Release Notes: - Added icons to the file finder. Screenshot: ![image](https://github.com/user-attachments/assets/bd6a54c1-cdbd-415a-9a82-0cc7a0bb6ca2) --------- Co-authored-by: Marshall Bowers --- Cargo.lock | 3 +++ assets/settings/default.json | 5 ++++ crates/file_finder/Cargo.toml | 3 +++ crates/file_finder/src/file_finder.rs | 21 +++++++++++++-- .../file_finder/src/file_finder_settings.rs | 27 +++++++++++++++++++ 5 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 crates/file_finder/src/file_finder_settings.rs diff --git a/Cargo.lock b/Cargo.lock index a19506829eeabf64567c49277f83b437f3f333ee..dd07dfa1cf08436060e58bce47dd96799a1a6d11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4326,6 +4326,7 @@ dependencies = [ "ctor", "editor", "env_logger", + "file_icons", "futures 0.3.30", "fuzzy", "gpui", @@ -4333,7 +4334,9 @@ dependencies = [ "menu", "picker", "project", + "schemars", "serde", + "serde_derive", "serde_json", "settings", "text", diff --git a/assets/settings/default.json b/assets/settings/default.json index 537ad120829b595a10a2b8b6a6e3787a4418815f..8424c5733d81bc856c38c4e322ee6bb6ea339a94 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -496,6 +496,11 @@ // Whether a preview tab gets replaced when code navigation is used to navigate away from the tab. "enable_preview_from_code_navigation": false }, + // Settings related to the file finder. + "file_finder": { + // Whether to show file icons in the file finder. + "file_icons": true + }, // Whether or not to remove any trailing whitespace from lines of a buffer // before saving it. "remove_trailing_whitespace_on_save": true, diff --git a/crates/file_finder/Cargo.toml b/crates/file_finder/Cargo.toml index 8f17b191a530730bac2f5678e6dc3cee94667dc5..2b4aa5fe3080cf6eeaca06ceb4f164b1cac3f562 100644 --- a/crates/file_finder/Cargo.toml +++ b/crates/file_finder/Cargo.toml @@ -16,14 +16,17 @@ doctest = false anyhow.workspace = true collections.workspace = true editor.workspace = true +file_icons.workspace = true futures.workspace = true fuzzy.workspace = true gpui.workspace = true menu.workspace = true picker.workspace = true project.workspace = true +schemars.workspace = true settings.workspace = true serde.workspace = true +serde_derive.workspace = true text.workspace = true theme.workspace = true ui.workspace = true diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 50a14b62dbb4d15b540325b04723f9ace7e129cc..e1e0998f8aa3b645c16750c8b2f9e537ca1aec57 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -1,11 +1,14 @@ #[cfg(test)] mod file_finder_tests; +mod file_finder_settings; mod new_path_prompt; mod open_path_prompt; use collections::HashMap; use editor::{scroll::Autoscroll, Bias, Editor}; +use file_finder_settings::FileFinderSettings; +use file_icons::FileIcons; use fuzzy::{CharBag, PathMatch, PathMatchCandidate}; use gpui::{ actions, rems, Action, AnyElement, AppContext, DismissEvent, EventEmitter, FocusHandle, @@ -39,7 +42,12 @@ pub struct FileFinder { init_modifiers: Option, } +pub fn init_settings(cx: &mut AppContext) { + FileFinderSettings::register(cx); +} + pub fn init(cx: &mut AppContext) { + init_settings(cx); cx.observe_new_views(FileFinder::register).detach(); cx.observe_new_views(NewPathPrompt::register).detach(); cx.observe_new_views(OpenPathPrompt::register).detach(); @@ -1041,12 +1049,14 @@ impl PickerDelegate for FileFinderDelegate { selected: bool, cx: &mut ViewContext>, ) -> Option { + let settings = FileFinderSettings::get_global(cx); + let path_match = self .matches .get(ix) .expect("Invalid matches state: no element for index {ix}"); - let icon = match &path_match { + let history_icon = match &path_match { Match::History { .. } => Icon::new(IconName::HistoryRerun) .color(Color::Muted) .size(IconSize::Small) @@ -1059,10 +1069,17 @@ impl PickerDelegate for FileFinderDelegate { let (file_name, file_name_positions, full_path, full_path_positions) = self.labels_for_match(path_match, cx, ix); + let file_icon = if settings.file_icons { + FileIcons::get_icon(Path::new(&file_name), cx).map(Icon::from_path) + } else { + None + }; + Some( ListItem::new(ix) .spacing(ListItemSpacing::Sparse) - .end_slot::(Some(icon)) + .start_slot::(file_icon) + .end_slot::(history_icon) .inset(true) .selected(selected) .child( diff --git a/crates/file_finder/src/file_finder_settings.rs b/crates/file_finder/src/file_finder_settings.rs new file mode 100644 index 0000000000000000000000000000000000000000..c02008c917b7fbcc0515524c4f94adc1521e3fd8 --- /dev/null +++ b/crates/file_finder/src/file_finder_settings.rs @@ -0,0 +1,27 @@ +use anyhow::Result; +use schemars::JsonSchema; +use serde_derive::{Deserialize, Serialize}; +use settings::{Settings, SettingsSources}; + +#[derive(Deserialize, Debug, Clone, Copy, PartialEq)] +pub struct FileFinderSettings { + pub file_icons: bool, +} + +#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)] +pub struct FileFinderSettingsContent { + /// Whether to show file icons in the file finder. + /// + /// Default: true + pub file_icons: Option, +} + +impl Settings for FileFinderSettings { + const KEY: Option<&'static str> = Some("file_finder"); + + type FileContent = FileFinderSettingsContent; + + fn load(sources: SettingsSources, _: &mut gpui::AppContext) -> Result { + sources.json_merge() + } +}